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.
This commit is contained in:
parent
0c650d4276
commit
b75cb8392b
|
@ -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
|
||||
|
|
|
@ -20,3 +20,8 @@ print(float('.' + '9' * 70 + 'e-50') == float('1e-50'))
|
|||
print(float('.' + '0' * 60 + '1e10') == float('1e-51'))
|
||||
print(float('.' + '0' * 60 + '9e25'))
|
||||
print(float('.' + '0' * 60 + '9e40'))
|
||||
|
||||
# ensure that accuracy is retained when value is close to a subnormal
|
||||
print(float('1.00000000000000000000e-37'))
|
||||
print(float('10.0000000000000000000e-38'))
|
||||
print(float('100.000000000000000000e-39'))
|
||||
|
|
|
@ -14,3 +14,8 @@ print(float('.' + '9' * 400 + 'e-100'))
|
|||
print(float('.' + '0' * 400 + '9e100'))
|
||||
print(float('.' + '0' * 400 + '9e200'))
|
||||
print(float('.' + '0' * 400 + '9e400'))
|
||||
|
||||
# ensure that accuracy is retained when value is close to a subnormal
|
||||
print(float('1.00000000000000000000e-307'))
|
||||
print(float('10.0000000000000000000e-308'))
|
||||
print(float('100.000000000000000000e-309'))
|
||||
|
|
Loading…
Reference in New Issue