Files
Mykhailo ShevchukandClaude Opus 5 5082af55ba Core: parse decimals directly instead of via newlib's strtod (-7,424 B) (#1186)
`__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>
2026-10-21 15:43:24 +03:00
..
2025-03-31 08:24:27 +04:00