Upgrade math,cmath to 3.14.2 and totally delegate to pymath (#6705)

* Upgrade test_math, test_cmath from 3.14.2

* pymath 0.1.5
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-01-13 22:05:32 +09:00
1 parent e91bc11b0a
commit f9e2f9d273
9 files changed
+783 -859

No files matched your search

Generated
+7 -2
View File
@@ -2450,11 +2450,16 @@ dependencies = [
[[package]]
name = "pymath"
version = "0.0.2"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b66ab66a8610ce209d8b36cd0fecc3a15c494f715e0cb26f0586057f293abc9"
checksum = "bbfb6723b732fc7f0b29a0ee7150c7f70f947bf467b8c3e82530b13589a78b4c"
dependencies = [
"libc",
"libm",
"malachite-bigint",
"num-complex",
"num-integer",
"num-traits",
]
[[package]]
+2 -1
View File
@@ -116,6 +116,7 @@ members = [
".",
"crates/*",
]
exclude = ["pymath"]
[workspace.package]
version = "0.4.0"
@@ -184,7 +185,7 @@ once_cell = "1.20.3"
parking_lot = "0.12.3"
paste = "1.0.15"
proc-macro2 = "1.0.105"
pymath = "0.0.2"
pymath = { version = "0.1.5", features = ["mul_add", "malachite-bigint", "complex"] }
quote = "1.0.43"
radium = "1.1.1"
rand = "0.9"
+14 -14
View File
@@ -371,9 +371,9 @@ acosh1002 acosh 0.0 inf -> inf 1.5707963267948966
acosh1003 acosh 2.3 inf -> inf 1.5707963267948966
acosh1004 acosh -0.0 inf -> inf 1.5707963267948966
acosh1005 acosh -2.3 inf -> inf 1.5707963267948966
acosh1006 acosh 0.0 nan -> nan nan
acosh1006 acosh 0.0 nan -> nan 1.5707963267948966 ignore-imag-sign
acosh1007 acosh 2.3 nan -> nan nan
acosh1008 acosh -0.0 nan -> nan nan
acosh1008 acosh -0.0 nan -> nan 1.5707963267948966 ignore-imag-sign
acosh1009 acosh -2.3 nan -> nan nan
acosh1010 acosh -inf 0.0 -> inf 3.1415926535897931
acosh1011 acosh -inf 2.3 -> inf 3.1415926535897931
@@ -1992,9 +1992,9 @@ tanh0065 tanh 1.797e+308 0.0 -> 1.0 0.0
--special values
tanh1000 tanh 0.0 0.0 -> 0.0 0.0
tanh1001 tanh 0.0 inf -> nan nan invalid
tanh1001 tanh 0.0 inf -> 0.0 nan invalid
tanh1002 tanh 2.3 inf -> nan nan invalid
tanh1003 tanh 0.0 nan -> nan nan
tanh1003 tanh 0.0 nan -> 0.0 nan
tanh1004 tanh 2.3 nan -> nan nan
tanh1005 tanh inf 0.0 -> 1.0 0.0
tanh1006 tanh inf 0.7 -> 1.0 0.0
@@ -2009,7 +2009,7 @@ tanh1014 tanh nan 2.3 -> nan nan
tanh1015 tanh nan inf -> nan nan
tanh1016 tanh nan nan -> nan nan
tanh1017 tanh 0.0 -0.0 -> 0.0 -0.0
tanh1018 tanh 0.0 -inf -> nan nan invalid
tanh1018 tanh 0.0 -inf -> 0.0 nan invalid
tanh1019 tanh 2.3 -inf -> nan nan invalid
tanh1020 tanh inf -0.0 -> 1.0 -0.0
tanh1021 tanh inf -0.7 -> 1.0 -0.0
@@ -2022,9 +2022,9 @@ tanh1027 tanh nan -0.0 -> nan -0.0
tanh1028 tanh nan -2.3 -> nan nan
tanh1029 tanh nan -inf -> nan nan
tanh1030 tanh -0.0 -0.0 -> -0.0 -0.0
tanh1031 tanh -0.0 -inf -> nan nan invalid
tanh1031 tanh -0.0 -inf -> -0.0 nan invalid
tanh1032 tanh -2.3 -inf -> nan nan invalid
tanh1033 tanh -0.0 nan -> nan nan
tanh1033 tanh -0.0 nan -> -0.0 nan
tanh1034 tanh -2.3 nan -> nan nan
tanh1035 tanh -inf -0.0 -> -1.0 -0.0
tanh1036 tanh -inf -0.7 -> -1.0 -0.0
@@ -2035,7 +2035,7 @@ tanh1040 tanh -inf -3.5 -> -1.0 -0.0
tanh1041 tanh -inf -inf -> -1.0 0.0 ignore-imag-sign
tanh1042 tanh -inf nan -> -1.0 0.0 ignore-imag-sign
tanh1043 tanh -0.0 0.0 -> -0.0 0.0
tanh1044 tanh -0.0 inf -> nan nan invalid
tanh1044 tanh -0.0 inf -> -0.0 nan invalid
tanh1045 tanh -2.3 inf -> nan nan invalid
tanh1046 tanh -inf 0.0 -> -1.0 0.0
tanh1047 tanh -inf 0.7 -> -1.0 0.0
@@ -2307,9 +2307,9 @@ tan0066 tan -8.79645943005142 0.0 -> 0.7265425280053614098 0.0
-- special values
tan1000 tan -0.0 0.0 -> -0.0 0.0
tan1001 tan -inf 0.0 -> nan nan invalid
tan1001 tan -inf 0.0 -> nan 0.0 invalid
tan1002 tan -inf 2.2999999999999998 -> nan nan invalid
tan1003 tan nan 0.0 -> nan nan
tan1003 tan nan 0.0 -> nan 0.0
tan1004 tan nan 2.2999999999999998 -> nan nan
tan1005 tan -0.0 inf -> -0.0 1.0
tan1006 tan -0.69999999999999996 inf -> -0.0 1.0
@@ -2324,7 +2324,7 @@ tan1014 tan -2.2999999999999998 nan -> nan nan
tan1015 tan -inf nan -> nan nan
tan1016 tan nan nan -> nan nan
tan1017 tan 0.0 0.0 -> 0.0 0.0
tan1018 tan inf 0.0 -> nan nan invalid
tan1018 tan inf 0.0 -> nan 0.0 invalid
tan1019 tan inf 2.2999999999999998 -> nan nan invalid
tan1020 tan 0.0 inf -> 0.0 1.0
tan1021 tan 0.69999999999999996 inf -> 0.0 1.0
@@ -2337,9 +2337,9 @@ tan1027 tan 0.0 nan -> 0.0 nan
tan1028 tan 2.2999999999999998 nan -> nan nan
tan1029 tan inf nan -> nan nan
tan1030 tan 0.0 -0.0 -> 0.0 -0.0
tan1031 tan inf -0.0 -> nan nan invalid
tan1031 tan inf -0.0 -> nan -0.0 invalid
tan1032 tan inf -2.2999999999999998 -> nan nan invalid
tan1033 tan nan -0.0 -> nan nan
tan1033 tan nan -0.0 -> nan -0.0
tan1034 tan nan -2.2999999999999998 -> nan nan
tan1035 tan 0.0 -inf -> 0.0 -1.0
tan1036 tan 0.69999999999999996 -inf -> 0.0 -1.0
@@ -2350,7 +2350,7 @@ tan1040 tan 3.5 -inf -> 0.0 -1.0
tan1041 tan inf -inf -> -0.0 -1.0 ignore-real-sign
tan1042 tan nan -inf -> -0.0 -1.0 ignore-real-sign
tan1043 tan -0.0 -0.0 -> -0.0 -0.0
tan1044 tan -inf -0.0 -> nan nan invalid
tan1044 tan -inf -0.0 -> nan -0.0 invalid
tan1045 tan -inf -2.2999999999999998 -> nan nan invalid
tan1046 tan -0.0 -inf -> -0.0 -1.0
tan1047 tan -0.69999999999999996 -inf -> -0.0 -1.0
+9 -9
View File
@@ -116,7 +116,7 @@ inf
>>> 0 ** -1
Traceback (most recent call last):
...
ZeroDivisionError: 0.0 cannot be raised to a negative power
ZeroDivisionError: zero to a negative power
>>> pow(0, NAN)
nan
@@ -127,31 +127,31 @@ Trigonometric Functions
>>> sin(INF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got inf
>>> sin(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got -inf
>>> sin(NAN)
nan
>>> cos(INF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got inf
>>> cos(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got -inf
>>> cos(NAN)
nan
>>> tan(INF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got inf
>>> tan(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a finite input, got -inf
>>> tan(NAN)
nan
@@ -169,11 +169,11 @@ True
>>> asin(INF), asin(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a number in range from -1 up to 1, got inf
>>> acos(INF), acos(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
ValueError: expected a number in range from -1 up to 1, got inf
>>> equal(atan(INF), PI/2), equal(atan(NINF), -PI/2)
(True, True)
-4
View File
@@ -276,7 +276,6 @@ class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase):
self.rAssertAlmostEqual(math.log(v, base), z.real)
self.assertEqual(0., z.imag)
@unittest.expectedFailure # TODO: RUSTPYTHON
@requires_IEEE_754
def test_specific_values(self):
# Some tests need to be skipped on ancient OS X versions.
@@ -530,13 +529,11 @@ class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase):
# log1p function; If that system function doesn't respect the sign
# of zero, then atan and atanh will also have difficulties with
# the sign of complex zeros.
@unittest.expectedFailure # TODO: RUSTPYTHON
@requires_IEEE_754
def testAtanSign(self):
for z in complex_zeros:
self.assertComplexesAreIdentical(cmath.atan(z), z)
@unittest.expectedFailure # TODO: RUSTPYTHON
@requires_IEEE_754
def testAtanhSign(self):
for z in complex_zeros:
@@ -583,7 +580,6 @@ class IsCloseTests(test_math.IsCloseTests):
self.assertIsClose(0.001-0.001j, 0.001+0.001j, abs_tol=2e-03)
self.assertIsNotClose(0.001-0.001j, 0.001+0.001j, abs_tol=1e-03)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_complex_special(self):
self.assertIsNotClose(INF, INF*1j)
self.assertIsNotClose(INF*1j, INF)
+62 -2
View File
@@ -573,6 +573,8 @@ class MathTests(unittest.TestCase):
#self.assertEqual(math.ceil(NINF), NINF)
#self.assertTrue(math.isnan(math.floor(NAN)))
class TestFloorIsNone(float):
__floor__ = None
class TestFloor:
def __floor__(self):
return 42
@@ -588,6 +590,7 @@ class MathTests(unittest.TestCase):
self.assertEqual(math.floor(FloatLike(41.9)), 41)
self.assertRaises(TypeError, math.floor, TestNoFloor())
self.assertRaises(ValueError, math.floor, TestBadFloor())
self.assertRaises(TypeError, math.floor, TestFloorIsNone(3.5))
t = TestNoFloor()
t.__floor__ = lambda *args: args
@@ -1125,6 +1128,15 @@ class MathTests(unittest.TestCase):
with self.assertRaises(TypeError):
math.isqrt(value)
@support.bigmemtest(2**32, memuse=0.85)
def test_isqrt_huge(self, size):
if size & 1:
size += 1
v = 1 << size
w = math.isqrt(v)
self.assertEqual(w.bit_length(), size // 2 + 1)
self.assertEqual(w.bit_count(), 1)
def test_lcm(self):
lcm = math.lcm
self.assertEqual(lcm(0, 0), 0)
@@ -1272,6 +1284,13 @@ class MathTests(unittest.TestCase):
self.assertEqual(math.log(INF), INF)
self.assertTrue(math.isnan(math.log10(NAN)))
@support.bigmemtest(2**32, memuse=0.2)
def test_log_huge_integer(self, size):
v = 1 << size
self.assertAlmostEqual(math.log2(v), size)
self.assertAlmostEqual(math.log(v), size * 0.6931471805599453)
self.assertAlmostEqual(math.log10(v), size * 0.3010299956639812)
def testSumProd(self):
sumprod = math.sumprod
Decimal = decimal.Decimal
@@ -1380,7 +1399,6 @@ class MathTests(unittest.TestCase):
self.assertEqual(sumprod([True, False] * 10, [0.1] * 20), 1.0)
self.assertEqual(sumprod([1.0, 10E100, 1.0, -10E100], [1.0]*4), 2.0)
@unittest.skip("TODO: RUSTPYTHON, Taking a few minutes.")
@support.requires_resource('cpu')
def test_sumprod_stress(self):
sumprod = math.sumprod
@@ -2020,7 +2038,6 @@ class MathTests(unittest.TestCase):
else:
self.fail("sqrt(-1) didn't raise ValueError")
@unittest.expectedFailure # TODO: RUSTPYTHON
@requires_IEEE_754
def test_testfile(self):
# Some tests need to be skipped on ancient OS X versions.
@@ -2495,6 +2512,46 @@ class MathTests(unittest.TestCase):
self.assertRaises(TypeError, math.atan2, 1.0)
self.assertRaises(TypeError, math.atan2, 1.0, 2.0, 3.0)
def test_exception_messages(self):
x = -1.1
with self.assertRaisesRegex(ValueError,
f"expected a nonnegative input, got {x}"):
math.sqrt(x)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log(x)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log(123, x)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log(x, 123)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log2(x)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log10(x)
x = decimal.Decimal('-1.1')
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {x}"):
math.log(x)
x = fractions.Fraction(1, 10**400)
with self.assertRaisesRegex(ValueError,
f"expected a positive input, got {float(x)}"):
math.log(x)
x = -123
with self.assertRaisesRegex(ValueError,
"expected a positive input$"):
math.log(x)
with self.assertRaisesRegex(ValueError,
f"expected a noninteger or positive integer, got {x}"):
math.gamma(x)
x = 1.0
with self.assertRaisesRegex(ValueError,
f"expected a number between -1 and 1, got {x}"):
math.atanh(x)
# Custom assertions.
def assertIsNaN(self, value):
@@ -2724,6 +2781,9 @@ class FMATests(unittest.TestCase):
or (sys.platform == "android" and platform.machine() == "x86_64")
or support.linked_to_musl(), # gh-131032
f"this platform doesn't implement IEE 754-2008 properly")
# gh-131032: musl is fixed but the fix is not yet released; when the fixed
# version is known change this to:
# or support.linked_to_musl() < (1, <m>, <p>)
def test_fma_zero_result(self):
nonnegative_finites = [0.0, 1e-300, 2.3, 1e300]
+65 -104
View File
@@ -1,6 +1,5 @@
// TODO: Keep track of rust-num/num-complex/issues/2. A common trait could help with duplication
// that exists between cmath and math.
pub(crate) use cmath::make_module;
#[pymodule]
mod cmath {
use crate::vm::{
@@ -9,137 +8,141 @@ mod cmath {
};
use num_complex::Complex64;
use crate::math::pymath_exception;
// Constants
#[pyattr]
use core::f64::consts::{E as e, PI as pi, TAU as tau};
#[pyattr(name = "e")]
const E: f64 = pymath::cmath::E;
#[pyattr(name = "pi")]
const PI: f64 = pymath::cmath::PI;
#[pyattr(name = "tau")]
const TAU: f64 = pymath::cmath::TAU;
#[pyattr(name = "inf")]
const INF: f64 = f64::INFINITY;
const INF: f64 = pymath::cmath::INF;
#[pyattr(name = "nan")]
const NAN: f64 = f64::NAN;
const NAN: f64 = pymath::cmath::NAN;
#[pyattr(name = "infj")]
const INFJ: Complex64 = Complex64::new(0., f64::INFINITY);
const INFJ: Complex64 = pymath::cmath::INFJ;
#[pyattr(name = "nanj")]
const NANJ: Complex64 = Complex64::new(0., f64::NAN);
const NANJ: Complex64 = pymath::cmath::NANJ;
#[pyfunction]
fn phase(z: ArgIntoComplex) -> f64 {
z.into_complex().arg()
fn phase(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<f64> {
pymath::cmath::phase(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn polar(x: ArgIntoComplex) -> (f64, f64) {
x.into_complex().to_polar()
fn polar(x: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<(f64, f64)> {
pymath::cmath::polar(x.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn rect(r: ArgIntoFloat, phi: ArgIntoFloat) -> Complex64 {
Complex64::from_polar(r.into_float(), phi.into_float())
fn rect(r: ArgIntoFloat, phi: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::rect(r.into_float(), phi.into_float())
.map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn isinf(z: ArgIntoComplex) -> bool {
let Complex64 { re, im } = z.into_complex();
re.is_infinite() || im.is_infinite()
pymath::cmath::isinf(z.into_complex())
}
#[pyfunction]
fn isfinite(z: ArgIntoComplex) -> bool {
z.into_complex().is_finite()
pymath::cmath::isfinite(z.into_complex())
}
#[pyfunction]
fn isnan(z: ArgIntoComplex) -> bool {
z.into_complex().is_nan()
pymath::cmath::isnan(z.into_complex())
}
#[pyfunction]
fn exp(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
let z = z.into_complex();
result_or_overflow(z, z.exp(), vm)
pymath::cmath::exp(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn sqrt(z: ArgIntoComplex) -> Complex64 {
z.into_complex().sqrt()
fn sqrt(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::sqrt(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn sin(z: ArgIntoComplex) -> Complex64 {
z.into_complex().sin()
fn sin(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::sin(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn asin(z: ArgIntoComplex) -> Complex64 {
z.into_complex().asin()
fn asin(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::asin(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn cos(z: ArgIntoComplex) -> Complex64 {
z.into_complex().cos()
fn cos(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::cos(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn acos(z: ArgIntoComplex) -> Complex64 {
z.into_complex().acos()
fn acos(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::acos(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn log(z: ArgIntoComplex, base: OptionalArg<ArgIntoComplex>) -> Complex64 {
// TODO: Complex64.log with a negative base yields wrong results.
// Issue is with num_complex::Complex64 implementation of log
// which returns NaN when base is negative.
// log10(z) / log10(base) yields correct results but division
// doesn't handle pos/neg zero nicely. (i.e log(1, 0.5))
z.into_complex().log(
base.into_option()
.map(|base| base.into_complex().re)
.unwrap_or(core::f64::consts::E),
fn log(
z: ArgIntoComplex,
base: OptionalArg<ArgIntoComplex>,
vm: &VirtualMachine,
) -> PyResult<Complex64> {
pymath::cmath::log(
z.into_complex(),
base.into_option().map(|b| b.into_complex()),
)
.map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn log10(z: ArgIntoComplex) -> Complex64 {
z.into_complex().log(10.0)
fn log10(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::log10(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn acosh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().acosh()
fn acosh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::acosh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn atan(z: ArgIntoComplex) -> Complex64 {
z.into_complex().atan()
fn atan(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::atan(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn atanh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().atanh()
fn atanh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::atanh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn tan(z: ArgIntoComplex) -> Complex64 {
z.into_complex().tan()
fn tan(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::tan(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn tanh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().tanh()
fn tanh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::tanh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn sinh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().sinh()
fn sinh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::sinh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn cosh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().cosh()
fn cosh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::cosh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[pyfunction]
fn asinh(z: ArgIntoComplex) -> Complex64 {
z.into_complex().asinh()
fn asinh(z: ArgIntoComplex, vm: &VirtualMachine) -> PyResult<Complex64> {
pymath::cmath::asinh(z.into_complex()).map_err(|err| pymath_exception(err, vm))
}
#[derive(FromArgs)]
@@ -158,52 +161,10 @@ mod cmath {
fn isclose(args: IsCloseArgs, vm: &VirtualMachine) -> PyResult<bool> {
let a = args.a.into_complex();
let b = args.b.into_complex();
let rel_tol = args.rel_tol.map_or(1e-09, |v| v.into_float());
let abs_tol = args.abs_tol.map_or(0.0, |v| v.into_float());
let rel_tol = args.rel_tol.into_option().map(|v| v.into_float());
let abs_tol = args.abs_tol.into_option().map(|v| v.into_float());
if rel_tol < 0.0 || abs_tol < 0.0 {
return Err(vm.new_value_error("tolerances must be non-negative"));
}
if a == b {
/* short circuit exact equality -- needed to catch two infinities of
the same sign. And perhaps speeds things up a bit sometimes.
*/
return Ok(true);
}
/* This catches the case of two infinities of opposite sign, or
one infinity and one finite number. Two infinities of opposite
sign would otherwise have an infinite relative tolerance.
Two infinities of the same sign are caught by the equality check
above.
*/
if a.is_infinite() || b.is_infinite() {
return Ok(false);
}
let diff = c_abs(b - a);
Ok(diff <= (rel_tol * c_abs(b)) || (diff <= (rel_tol * c_abs(a))) || diff <= abs_tol)
}
#[inline]
fn c_abs(Complex64 { re, im }: Complex64) -> f64 {
re.hypot(im)
}
#[inline]
fn result_or_overflow(
value: Complex64,
result: Complex64,
vm: &VirtualMachine,
) -> PyResult<Complex64> {
if !result.is_finite() && value.is_finite() {
// CPython doesn't return `inf` when called with finite
// values, it raises OverflowError instead.
Err(vm.new_overflow_error("math range error"))
} else {
Ok(result)
}
pymath::cmath::isclose(a, b, rel_tol, abs_tol)
.map_err(|_| vm.new_value_error("tolerances must be non-negative"))
}
}
+623 -722
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -116,7 +116,7 @@ fn inner_divmod(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult<(f64, f64)> {
pub fn float_pow(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult {
if v1.is_zero() && v2.is_sign_negative() {
let msg = "0.0 cannot be raised to a negative power";
let msg = "zero to a negative power";
Err(vm.new_zero_division_error(msg.to_owned()))
} else if v1.is_sign_negative() && (v2.floor() - v2).abs() > f64::EPSILON {
let v1 = Complex64::new(v1, 0.);