mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
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:
1 parent
e91bc11b0a
commit
f9e2f9d273
9 files changed
+783
-859
No files matched your search
Generated
+7
-2
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Vendored
+9
-9
@@ -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)
|
||||
|
||||
|
||||
Vendored
-4
@@ -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)
|
||||
|
||||
Vendored
+62
-2
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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.);
|
||||
|
||||
Reference in new issue
Block a user