summaryrefslogtreecommitdiffstatshomepage
path: root/py/parsenum.c
diff options
context:
space:
mode:
authorYoctopuce dev <dev@yoctopuce.com>2025-01-30 10:23:06 +0100
committerDamien George <damien@micropython.org>2025-02-28 13:35:12 +1100
commit5fdd249c55d44ed0513e931c9b7364dd8b3454d9 (patch)
tree7ed451b4800fc10ad14cb0e91b3473a612ed0005 /py/parsenum.c
parent50fab08e6b861adf65905d6adacd74201c87ddb9 (diff)
downloadmicropython-5fdd249c55d44ed0513e931c9b7364dd8b3454d9.tar.gz
micropython-5fdd249c55d44ed0513e931c9b7364dd8b3454d9.zip
py/parsenum: Reduce code footprint of mp_parse_num_float.
The mantissa parsing code uses a floating point variable to accumulate digits. Using an `mp_float_uint_t` variable instead and casting to `mp_float_t` at the very end reduces code size. In some cases, it also improves the rounding behaviour as extra digits are taken into account by the int-to-float conversion code. An extra test case handles the special case where mantissa overflow occurs while processing deferred trailing zeros. Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
Diffstat (limited to 'py/parsenum.c')
-rw-r--r--py/parsenum.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/py/parsenum.c b/py/parsenum.c
index 27d6641198..3281eb4b85 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -179,39 +179,40 @@ typedef enum {
} parse_dec_in_t;
#if MICROPY_PY_BUILTINS_FLOAT
-// DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing
+// MANTISSA_MAX is used to retain precision while not overflowing mantissa
// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float
// EXACT_POWER_OF_10 is the largest value of x so that 10^x can be stored exactly in a float
// Note: EXACT_POWER_OF_10 is at least floor(log_5(2^mantissa_length)). Indeed, 10^n = 2^n * 5^n
// so we only have to store the 5^n part in the mantissa (the 2^n part will go into the float's
// exponent).
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
-#define DEC_VAL_MAX 1e20F
+#define MANTISSA_MAX 0x19999998U
#define SMALL_NORMAL_VAL (1e-37F)
#define SMALL_NORMAL_EXP (-37)
#define EXACT_POWER_OF_10 (9)
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
-#define DEC_VAL_MAX 1e200
+#define MANTISSA_MAX 0x1999999999999998ULL
#define SMALL_NORMAL_VAL (1e-307)
#define SMALL_NORMAL_EXP (-307)
#define EXACT_POWER_OF_10 (22)
#endif
// Break out inner digit accumulation routine to ease trailing zero deferral.
-static void accept_digit(mp_float_t *p_dec_val, int dig, int *p_exp_extra, int in) {
+static mp_float_uint_t accept_digit(mp_float_uint_t p_mantissa, unsigned int dig, int *p_exp_extra, int in) {
// Core routine to ingest an additional digit.
- if (*p_dec_val < DEC_VAL_MAX) {
+ if (p_mantissa < MANTISSA_MAX) {
// dec_val won't overflow so keep accumulating
- *p_dec_val = 10 * *p_dec_val + dig;
if (in == PARSE_DEC_IN_FRAC) {
--(*p_exp_extra);
}
+ return 10u * p_mantissa + dig;
} else {
// dec_val might overflow and we anyway can't represent more digits
// of precision, so ignore the digit and just adjust the exponent
if (in == PARSE_DEC_IN_INTG) {
++(*p_exp_extra);
}
+ return p_mantissa;
}
}
#endif // MICROPY_PY_BUILTINS_FLOAT
@@ -273,6 +274,7 @@ parse_start:
// string should be a decimal number
parse_dec_in_t in = PARSE_DEC_IN_INTG;
bool exp_neg = false;
+ mp_float_uint_t mantissa = 0;
int exp_val = 0;
int exp_extra = 0;
int trailing_zeros_intg = 0, trailing_zeros_frac = 0;
@@ -288,9 +290,9 @@ parse_start:
exp_val = 10 * exp_val + dig;
}
} else {
- if (dig == 0 || dec_val >= DEC_VAL_MAX) {
+ if (dig == 0 || mantissa >= MANTISSA_MAX) {
// Defer treatment of zeros in fractional part. If nothing comes afterwards, ignore them.
- // Also, once we reach DEC_VAL_MAX, treat every additional digit as a trailing zero.
+ // Also, once we reach MANTISSA_MAX, treat every additional digit as a trailing zero.
if (in == PARSE_DEC_IN_INTG) {
++trailing_zeros_intg;
} else {
@@ -299,14 +301,14 @@ parse_start:
} else {
// Time to un-defer any trailing zeros. Intg zeros first.
while (trailing_zeros_intg) {
- accept_digit(&dec_val, 0, &exp_extra, PARSE_DEC_IN_INTG);
+ mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_INTG);
--trailing_zeros_intg;
}
while (trailing_zeros_frac) {
- accept_digit(&dec_val, 0, &exp_extra, PARSE_DEC_IN_FRAC);
+ mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_FRAC);
--trailing_zeros_frac;
}
- accept_digit(&dec_val, dig, &exp_extra, in);
+ mantissa = accept_digit(mantissa, dig, &exp_extra, in);
}
}
} else if (in == PARSE_DEC_IN_INTG && dig == '.') {
@@ -340,6 +342,7 @@ parse_start:
// apply the exponent, making sure it's not a subnormal value
exp_val += exp_extra + trailing_zeros_intg;
+ dec_val = (mp_float_t)mantissa;
if (exp_val < SMALL_NORMAL_EXP) {
exp_val -= SMALL_NORMAL_EXP;
dec_val *= SMALL_NORMAL_VAL;