mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Fix negative ** fraction to returns complex value
Fix #1986 which (-2) ** 0.5 yields NaN. Result: RustPython gives `float.__rpow__(0.5, -2) (0.00000000000000008659560562354934+1.4142135623730951j)` CPython 3.85 gives `>>> float.__rpow__(0.5, -2) (8.659560562354934e-17+1.4142135623730951j)`
This commit is contained in:
1 parent
d193587184
commit
6032b54666
2 files changed
+20
-6
No files matched your search
@@ -392,8 +392,6 @@ class FractionTest(unittest.TestCase):
|
||||
self.assertTypedEquals(F(-2, 10), round(F(-15, 100), 1))
|
||||
self.assertTypedEquals(F(-2, 10), round(F(-25, 100), 1))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def testArithmetic(self):
|
||||
self.assertEqual(F(1, 2), F(1, 10) + F(2, 5))
|
||||
self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5))
|
||||
|
||||
+20
-4
@@ -1,4 +1,5 @@
|
||||
use num_bigint::{BigInt, ToBigInt};
|
||||
use num_complex::Complex64;
|
||||
use num_rational::Ratio;
|
||||
use num_traits::{pow, ToPrimitive, Zero};
|
||||
|
||||
@@ -134,12 +135,16 @@ fn inner_divmod(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult<(f64, f64)> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float_pow(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult<f64> {
|
||||
pub fn float_pow(v1: f64, v2: f64, vm: &VirtualMachine) -> PyResult {
|
||||
if v1.is_zero() {
|
||||
let msg = format!("{} cannot be raised to a negative power", v1);
|
||||
Err(vm.new_zero_division_error(msg))
|
||||
} else if v1.is_sign_negative() && (v2.floor() - v2).abs() > f64::EPSILON {
|
||||
let v1 = Complex64::new(v1, 0.);
|
||||
let v2 = Complex64::new(v2, 0.);
|
||||
v1.powc(v2).into_pyobject(vm)
|
||||
} else {
|
||||
Ok(v1.powf(v2))
|
||||
v1.powf(v2).into_pyobject(vm)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +263,17 @@ impl PyFloat {
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn complex_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult
|
||||
where
|
||||
F: Fn(f64, f64) -> PyResult,
|
||||
{
|
||||
try_float(&other, vm)?.map_or_else(
|
||||
|| Ok(vm.ctx.not_implemented()),
|
||||
|other| op(self.value, other).into_pyobject(vm),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tuple_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyResult
|
||||
where
|
||||
@@ -331,12 +347,12 @@ impl PyFloat {
|
||||
|
||||
#[pymethod(name = "__pow__")]
|
||||
fn pow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.simple_op(other, |a, b| float_pow(a, b, vm), vm)
|
||||
self.complex_op(other, |a, b| float_pow(a, b, vm), vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rpow__")]
|
||||
fn rpow(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
|
||||
self.simple_op(other, |a, b| float_pow(b, a, vm), vm)
|
||||
self.complex_op(other, |a, b| float_pow(b, a, vm), vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__sub__")]
|
||||
|
||||
Reference in new issue
Block a user