Skip to content

Commit 82b4990

Browse files
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).
1 parent 247072c commit 82b4990

File tree

3 files changed

+11
-26
lines changed

3 files changed

+11
-26
lines changed

Lib/test/test_long.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,8 +514,6 @@ def test_float_overflow(self):
514514
self.assertNotEqual(float(shuge), int(shuge),
515515
"float(shuge) should not equal int(shuge)")
516516

517-
# TODO: RUSTPYTHON
518-
@unittest.expectedFailure
519517
def test_logs(self):
520518
LOG10E = math.log10(math.e)
521519

Lib/test/test_math.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,8 +1137,6 @@ def testLdexp(self):
11371137
self.assertEqual(math.ldexp(NINF, n), NINF)
11381138
self.assertTrue(math.isnan(math.ldexp(NAN, n)))
11391139

1140-
# TODO: RUSTPYTHON
1141-
@unittest.expectedFailure
11421140
def testLog(self):
11431141
self.assertRaises(TypeError, math.log)
11441142
self.ftest('log(1/e)', math.log(1/math.e), -1)
@@ -1190,8 +1188,6 @@ def testLog2Exact(self):
11901188
expected = [float(n) for n in range(-1074, 1024)]
11911189
self.assertEqual(actual, expected)
11921190

1193-
# TODO: RUSTPYTHON
1194-
@unittest.expectedFailure
11951191
def testLog10(self):
11961192
self.assertRaises(TypeError, math.log10)
11971193
self.ftest('log10(0.1)', math.log10(0.1), -1)

stdlib/src/math.rs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,9 @@ mod math {
132132
}
133133

134134
#[pyfunction]
135-
fn log(x: ArgIntoFloat, base: OptionalArg<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<f64> {
136-
let x = *x;
137-
base.map_or_else(
138-
|| {
139-
if x.is_nan() || x > 0.0_f64 {
140-
Ok(x.ln())
141-
} else {
142-
Err(vm.new_value_error("math domain error".to_owned()))
143-
}
144-
},
145-
|base| Ok(x.log(*base)),
146-
)
135+
fn log(x: PyObjectRef, base: OptionalArg<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<f64> {
136+
let base = base.map(|b| *b).unwrap_or(std::f64::consts::E);
137+
log2(x, vm).map(|logx| logx / base.log2())
147138
}
148139

149140
#[pyfunction]
@@ -179,7 +170,12 @@ mod math {
179170
}
180171
Err(float_err) => {
181172
if let Ok(x) = x.try_int(vm) {
182-
Ok(int_log2(x.as_bigint()))
173+
let x = x.as_bigint();
174+
if x > &BigInt::zero() {
175+
Ok(int_log2(x))
176+
} else {
177+
Err(vm.new_value_error("math domain error".to_owned()))
178+
}
183179
} else {
184180
// Return the float error, as it will be more intuitive to users
185181
Err(float_err)
@@ -189,13 +185,8 @@ mod math {
189185
}
190186

191187
#[pyfunction]
192-
fn log10(x: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> {
193-
let x = *x;
194-
if x.is_nan() || x > 0.0_f64 {
195-
Ok(x.log10())
196-
} else {
197-
Err(vm.new_value_error("math domain error".to_owned()))
198-
}
188+
fn log10(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
189+
log2(x, vm).map(|logx| logx / 10f64.log2())
199190
}
200191

201192
#[pyfunction]

0 commit comments

Comments
 (0)