py: Fix handling of NaN in certain pow implementations.

Adds a new compile-time option MICROPY_PY_MATH_POW_FIX_NAN for use with
toolchains that don't handle pow-of-NaN correctly.
pull/6399/head
stijn 2020-09-08 15:22:34 +02:00 zatwierdzone przez Damien George
rodzic 8d5a40c86e
commit 2e54d9d146
5 zmienionych plików z 26 dodań i 1 usunięć

Wyświetl plik

@ -236,6 +236,8 @@ extern const struct _mp_obj_module_t mp_module_time;
#define MICROPY_PY_MATH_FMOD_FIX_INFNAN (1) #define MICROPY_PY_MATH_FMOD_FIX_INFNAN (1)
#ifdef _WIN64 #ifdef _WIN64
#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (1) #define MICROPY_PY_MATH_MODF_FIX_NEGZERO (1)
#else
#define MICROPY_PY_MATH_POW_FIX_NAN (1)
#endif #endif
#endif #endif

Wyświetl plik

@ -98,7 +98,19 @@ mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
// sqrt(x): returns the square root of x // sqrt(x): returns the square root of x
MATH_FUN_1(sqrt, sqrt) MATH_FUN_1(sqrt, sqrt)
// pow(x, y): returns x to the power of y // pow(x, y): returns x to the power of y
#if MICROPY_PY_MATH_POW_FIX_NAN
mp_float_t pow_func(mp_float_t x, mp_float_t y) {
// pow(base, 0) returns 1 for any base, even when base is NaN
// pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN
if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) {
return MICROPY_FLOAT_CONST(1.0);
}
return MICROPY_FLOAT_C_FUN(pow)(x, y);
}
MATH_FUN_2(pow, pow_func)
#else
MATH_FUN_2(pow, pow) MATH_FUN_2(pow, pow)
#endif
// exp(x) // exp(x)
MATH_FUN_1(exp, exp) MATH_FUN_1(exp, exp)
#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS

Wyświetl plik

@ -1160,6 +1160,11 @@ typedef double mp_float_t;
#define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0) #define MICROPY_PY_MATH_MODF_FIX_NEGZERO (0)
#endif #endif
// Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN.
#ifndef MICROPY_PY_MATH_POW_FIX_NAN
#define MICROPY_PY_MATH_POW_FIX_NAN (0)
#endif
// Whether to provide "cmath" module // Whether to provide "cmath" module
#ifndef MICROPY_PY_CMATH #ifndef MICROPY_PY_CMATH
#define MICROPY_PY_CMATH (0) #define MICROPY_PY_CMATH (0)

Wyświetl plik

@ -300,6 +300,12 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported")); mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
#endif #endif
} }
#if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.
if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {
lhs_val = MICROPY_FLOAT_CONST(1.0);
break;
}
#endif
lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);
break; break;
case MP_BINARY_OP_DIVMOD: { case MP_BINARY_OP_DIVMOD: {

Wyświetl plik

@ -38,7 +38,7 @@ for name, f, args in (
# double argument functions # double argument functions
for name, f, args in ( for name, f, args in (
("pow", math.pow, ((0, 2), (-1, 2), (0, -1), (-1, 2.3))), ("pow", math.pow, ((0, 2), (-1, 2), (0, -1), (-1, 2.3), (nan, 0), (1, nan))),
("fmod", math.fmod, ((1.2, inf), (1.2, -inf), (1.2, 0), (inf, 1.2))), ("fmod", math.fmod, ((1.2, inf), (1.2, -inf), (1.2, 0), (inf, 1.2))),
("atan2", math.atan2, ((0, 0), (-inf, inf), (-inf, -inf), (inf, -inf))), ("atan2", math.atan2, ((0, 0), (-inf, inf), (-inf, -inf), (inf, -inf))),
("copysign", math.copysign, ()), ("copysign", math.copysign, ()),