py/modmath: Work around msvc float bugs in atan2, fmod and modf.
Older implementations deal with infinity/negative zero incorrectly. This commit adds generic fixes that can be enabled by any port that needs them, along with new tests cases.
This commit is contained in:
27
py/modmath.c
27
py/modmath.c
@@ -34,6 +34,8 @@
|
||||
// M_PI is not part of the math.h standard and may not be defined
|
||||
// And by defining our own we can ensure it uses the correct const format.
|
||||
#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
|
||||
#define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962)
|
||||
#define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885)
|
||||
|
||||
STATIC NORETURN void math_error(void) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("math domain error"));
|
||||
@@ -132,7 +134,17 @@ MATH_FUN_1(asin, asin)
|
||||
// atan(x)
|
||||
MATH_FUN_1(atan, atan)
|
||||
// atan2(y, x)
|
||||
#if MICROPY_PY_MATH_ATAN2_FIX_INFNAN
|
||||
mp_float_t atan2_func(mp_float_t x, mp_float_t y) {
|
||||
if (isinf(x) && isinf(y)) {
|
||||
return copysign(y < 0 ? MP_3_PI_4 : MP_PI_4, x);
|
||||
}
|
||||
return atan2(x, y);
|
||||
}
|
||||
MATH_FUN_2(atan2, atan2_func)
|
||||
#else
|
||||
MATH_FUN_2(atan2, atan2)
|
||||
#endif
|
||||
// ceil(x)
|
||||
MATH_FUN_1_TO_INT(ceil, ceil)
|
||||
// copysign(x, y)
|
||||
@@ -148,7 +160,14 @@ MATH_FUN_1(fabs, fabs_func)
|
||||
// floor(x)
|
||||
MATH_FUN_1_TO_INT(floor, floor) // TODO: delegate to x.__floor__() if x is not a float
|
||||
// fmod(x, y)
|
||||
#if MICROPY_PY_MATH_FMOD_FIX_INFNAN
|
||||
mp_float_t fmod_func(mp_float_t x, mp_float_t y) {
|
||||
return (!isinf(x) && isinf(y)) ? x : fmod(x, y);
|
||||
}
|
||||
MATH_FUN_2(fmod, fmod_func)
|
||||
#else
|
||||
MATH_FUN_2(fmod, fmod)
|
||||
#endif
|
||||
// isfinite(x)
|
||||
MATH_FUN_1_TO_BOOL(isfinite, isfinite)
|
||||
// isinf(x)
|
||||
@@ -246,7 +265,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
|
||||
// modf(x)
|
||||
STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {
|
||||
mp_float_t int_part = 0.0;
|
||||
mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
|
||||
mp_float_t x = mp_obj_get_float(x_obj);
|
||||
mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(x, &int_part);
|
||||
#if MICROPY_PY_MATH_MODF_FIX_NEGZERO
|
||||
if (fractional_part == MICROPY_FLOAT_CONST(0.0)) {
|
||||
fractional_part = copysign(fractional_part, x);
|
||||
}
|
||||
#endif
|
||||
mp_obj_t tuple[2];
|
||||
tuple[0] = mp_obj_new_float(fractional_part);
|
||||
tuple[1] = mp_obj_new_float(int_part);
|
||||
|
||||
Reference in New Issue
Block a user