diff --git a/src/bindings/py_number.c b/src/bindings/py_number.c index 7aeb49b6..683fee1f 100644 --- a/src/bindings/py_number.c +++ b/src/bindings/py_number.c @@ -384,7 +384,7 @@ static bool int__abs__(int argc, py_Ref argv) { static bool float__abs__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); py_f64 val = py_tofloat(&argv[0]); - py_newfloat(py_retval(), val < 0 ? -val : val); + py_newfloat(py_retval(), dmath_fabs(val)); return true; } diff --git a/src/common/dmath.c b/src/common/dmath.c index e587fdc3..fdcf4a38 100644 --- a/src/common/dmath.c +++ b/src/common/dmath.c @@ -701,8 +701,11 @@ double dmath_copysign(double x, double y) { return ux.f; } +// https://github.com/kraj/musl/blob/kraj/master/src/math/fabs.c double dmath_fabs(double x) { - return (x < 0) ? -x : x; + union Float64Bits u = { .f = x }; + u.i &= -1ULL/2; + return u.f; } double dmath_ceil(double x) { diff --git a/tests/020_float.py b/tests/020_float.py index 4652133a..9fa080ad 100644 --- a/tests/020_float.py +++ b/tests/020_float.py @@ -97,6 +97,9 @@ assert 3.4e+3 == 3400.0 assert abs(1.0) == 1.0 assert abs(-1.0) == 1.0 assert abs(0.0) == 0.0 +# abs(-0.0) is 0.0, not -0.0. `==` cannot tell them apart, so check the sign. +assert str(abs(-0.0)) == '0.0' +assert str(abs(0.0)) == '0.0' # import math # assert math.isnan(0/0)