mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-11-13 10:27:37 +00:00
`__wrap_strtof`/`__wrap_strtod` forwarded to newlib's `strtof_l`/`strtod_l`,
which pull in `_Balloc`/`__gethex` arbitrary-precision machinery for hex-float
literals, inf/nan spellings and correct rounding of long mantissas. That is
8,100 bytes of flash for input nothing passes them. What reaches these is file
fields (`flipper_format_stream.c:391`), CLI arguments (`args.c:45`, `args.c:126`)
and JS/JSON numbers (`mjs_tok.c`, `mjs_parser.c`, `mjs_json.c`) - plain decimal
literals in every case.
Parse it directly: accumulate a `uint64_t` mantissa and a decimal exponent,
then scale by binary exponentiation over a 9-entry power-of-ten table. An
integer needs no scaling at all, so it still converts exactly up to 2^53.
.text 700,256 -> 693,252 -7,004
.rodata 172,308 -> 171,888 -420
flash pages 214 -> 212
Checked by linking this file against the host libc and comparing every value
and tail pointer with the host's correctly-rounded `strtod`/`strtof` over
~480,000 inputs: no tail mismatch, worst 4 ulp as a double (0 ulp on 55% of
cases, >=3 ulp on 0.3%), denormals exact down to `5e-324`, and plain integers
to 2^53 at 0 ulp. `strtof` is bit-exact on everything `"%f"` emits, which is
the `.ir`/`.sub`/`.nfc` round-trip contract; it can differ by 1 float ulp when
a ~10-digit integer carries a ~10-digit fraction tail, because the double it
narrows from rounds twice.
These are exported to apps (`api_symbols.csv:3722-3725`), so the narrowed
contract is public and `wrappers.h` states it: no hex floats, no `inf`/`nan`
spellings, and a value within 2 ulp of `DBL_MAX` saturates to infinity.
`errno = ERANGE` on overflow and underflow is kept - `args_read_duration()`
checks it - and the tail pointer follows the standard throughout.
mJS special-cased hex for lowercase `0x` only and let `0X` fall through to
newlib's hex-float support, so `var a = 0X1A;` would have become a parse error.
Teach `mjs_tok.c` and `mjs_parser.c` the uppercase form instead.
No unit test: `FIRMWARE_APP_SET=unit_tests` does not link on dev, so one cannot
even be compiled. Filed as #1185; the test is ready to land once that is fixed.
Closes #1184
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>