summaryrefslogtreecommitdiffstatshomepage
path: root/py/modmath.c
diff options
context:
space:
mode:
authorstijn <stijn@ignitron.net>2020-05-17 12:29:25 +0200
committerDamien George <damien.p.george@gmail.com>2020-05-28 09:54:54 +1000
commit81db22f693d06468d45571a29fc0648a8f5664ce (patch)
treea4d0621aea1f0dc89ba14a9181b64903a54bc88e /py/modmath.c
parenta902b69dd51de0e3fe3bb6955296591d6a93abab (diff)
downloadmicropython-81db22f693d06468d45571a29fc0648a8f5664ce.tar.gz
micropython-81db22f693d06468d45571a29fc0648a8f5664ce.zip
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.
Diffstat (limited to 'py/modmath.c')
-rw-r--r--py/modmath.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/py/modmath.c b/py/modmath.c
index 5ff892ba11..b312eeb3d2 100644
--- a/py/modmath.c
+++ b/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);