Use improved log2() implementation for log10()

This also fixes a bug in the log2() implementation, where very large
negative integer arguments would not raise an exception (and instead
would turn into NaNs).
This commit is contained in:
Devon Hollowood committed 2022-10-24 18:46:49 -07:00
1 parent 247072c2cc
commit 82b4990224
3 files changed
+11 -26

No files matched your search

-2
View File
@@ -514,8 +514,6 @@ class LongTest(unittest.TestCase):
self.assertNotEqual(float(shuge), int(shuge),
"float(shuge) should not equal int(shuge)")
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_logs(self):
LOG10E = math.log10(math.e)
-4
View File
@@ -1137,8 +1137,6 @@ class MathTests(unittest.TestCase):
self.assertEqual(math.ldexp(NINF, n), NINF)
self.assertTrue(math.isnan(math.ldexp(NAN, n)))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testLog(self):
self.assertRaises(TypeError, math.log)
self.ftest('log(1/e)', math.log(1/math.e), -1)
@@ -1190,8 +1188,6 @@ class MathTests(unittest.TestCase):
expected = [float(n) for n in range(-1074, 1024)]
self.assertEqual(actual, expected)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testLog10(self):
self.assertRaises(TypeError, math.log10)
self.ftest('log10(0.1)', math.log10(0.1), -1)
+11 -20
View File
@@ -132,18 +132,9 @@ mod math {
}
#[pyfunction]
fn log(x: ArgIntoFloat, base: OptionalArg<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<f64> {
let x = *x;
base.map_or_else(
|| {
if x.is_nan() || x > 0.0_f64 {
Ok(x.ln())
} else {
Err(vm.new_value_error("math domain error".to_owned()))
}
},
|base| Ok(x.log(*base)),
)
fn log(x: PyObjectRef, base: OptionalArg<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<f64> {
let base = base.map(|b| *b).unwrap_or(std::f64::consts::E);
log2(x, vm).map(|logx| logx / base.log2())
}
#[pyfunction]
@@ -179,7 +170,12 @@ mod math {
}
Err(float_err) => {
if let Ok(x) = x.try_int(vm) {
Ok(int_log2(x.as_bigint()))
let x = x.as_bigint();
if x > &BigInt::zero() {
Ok(int_log2(x))
} else {
Err(vm.new_value_error("math domain error".to_owned()))
}
} else {
// Return the float error, as it will be more intuitive to users
Err(float_err)
@@ -189,13 +185,8 @@ mod math {
}
#[pyfunction]
fn log10(x: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> {
let x = *x;
if x.is_nan() || x > 0.0_f64 {
Ok(x.log10())
} else {
Err(vm.new_value_error("math domain error".to_owned()))
}
fn log10(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
log2(x, vm).map(|logx| logx / 10f64.log2())
}
#[pyfunction]