diff options
author | Damien George <damien.p.george@gmail.com> | 2018-02-08 14:02:50 +1100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2018-02-08 14:02:50 +1100 |
commit | b75cb8392bdf5f8c12072eac3adbdaad53d1e8d2 (patch) | |
tree | 4e02e3f9b22d6496677c97366d981778619556b9 /py/parsenum.c | |
parent | 0c650d427601d5c84bd623d58abc9be5451c576c (diff) |
py/parsenum: Fix parsing of floats that are close to subnormal.
Prior to this patch, a float literal that was close to subnormal would
have a loss of precision when parsed. The worst case was something like
float('10000000000000000000e-326') which returned 0.0.
Diffstat (limited to 'py/parsenum.c')
-rw-r--r-- | py/parsenum.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/py/parsenum.c b/py/parsenum.c index 98e773685..124489c66 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -172,10 +172,15 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool #if MICROPY_PY_BUILTINS_FLOAT // DEC_VAL_MAX only needs to be rough and is used to retain precision while not overflowing +// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define DEC_VAL_MAX 1e20F +#define SMALL_NORMAL_VAL (1e-37F) +#define SMALL_NORMAL_EXP (-37) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define DEC_VAL_MAX 1e200 +#define SMALL_NORMAL_VAL (1e-307) +#define SMALL_NORMAL_EXP (-307) #endif const char *top = str + len; @@ -275,8 +280,13 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool exp_val = -exp_val; } - // apply the exponent - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val + exp_extra); + // apply the exponent, making sure it's not a subnormal value + exp_val += exp_extra; + if (exp_val < SMALL_NORMAL_EXP) { + exp_val -= SMALL_NORMAL_EXP; + dec_val *= SMALL_NORMAL_VAL; + } + dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); } // negate value if needed |