Upgrade math,cmath to 3.14.2 and totally delegate to pymath by youknowone · Pull Request #6705 · RustPython/RustPython
fn log(x: PyObjectRef, base: OptionalArg<ArgIntoFloat>, vm: &VirtualMachine) -> PyResult<f64> {
let base: f64 = base.map(Into::into).unwrap_or(core::f64::consts::E);
if base.is_sign_negative() {
return Err(vm.new_value_error("math domain error"));
let base = base.into_option().map(|v| v.into_float());
// Check base first for proper error messages
if let Some(b) = base {
if b <= 0.0 {
return Err(vm.new_value_error(format!(
"expected a positive input, got {}",
super::float_repr(b)
)));
}
if b == 1.0 {
return Err(vm.new_value_error("math domain error".to_owned()));
}
}
// Handle BigInt specially for large values (only for actual int type, not float)
if let Some(i) = x.downcast_ref::<PyInt>() {
return pymath::math::log_bigint(i.as_bigint(), base).map_err(|err| match err {
pymath::Error::EDOM => vm.new_value_error("expected a positive input".to_owned()),
_ => pymath_exception(err, vm),
});
}
log2(x, vm).map(|log_x| log_x / base.log2())
let val = x.try_float(vm)?.to_f64();
pymath::math::log(val, base).map_err(|err| match err {
pymath::Error::EDOM => vm.new_value_error(format!(
"expected a positive input, got {}",
super::float_repr(val)
)),
_ => pymath_exception(err, vm),
})
}
#[pyfunction] fn log1p(x: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> { let x = x.into_float(); if x.is_nan() || x > -1.0_f64 { Ok(x.ln_1p()) } else { Err(vm.new_value_error("math domain error")) } }
/// Generates the base-2 logarithm of a BigInt `x` fn int_log2(x: &BigInt) -> f64 { // log2(x) = log2(2^n * 2^-n * x) = n + log2(x/2^n) // If we set 2^n to be the greatest power of 2 below x, then x/2^n is in [1, 2), and can // thus be converted into a float. let n = x.bits() as u32 - 1; let frac = true_div(x, &BigInt::from(2).pow(n)); f64::from(n) + frac.log2() pymath::math::log1p(x.into_float()).map_err(|err| pymath_exception(err, vm)) }
#[pyfunction] fn log2(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> { match x.try_float(vm) { Ok(x) => { let x = x.to_f64(); if x.is_nan() || x > 0.0_f64 { Ok(x.log2()) } else { Err(vm.new_value_error("math domain error")) } } Err(float_err) => { if let Ok(x) = x.try_int(vm) { let x = x.as_bigint(); if x.is_positive() { Ok(int_log2(x)) } else { Err(vm.new_value_error("math domain error")) } } else { // Return the float error, as it will be more intuitive to users Err(float_err) } } // Handle BigInt specially for large values (only for actual int type, not float) if let Some(i) = x.downcast_ref::<PyInt>() { return pymath::math::log2_bigint(i.as_bigint()).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error("expected a positive input".to_owned()), _ => pymath_exception(err, vm), }); } let val = x.try_float(vm)?.to_f64(); pymath::math::log2(val).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error(format!( "expected a positive input, got {}", super::float_repr(val) )), _ => pymath_exception(err, vm), }) }
#[pyfunction] fn log10(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> { log2(x, vm).map(|log_x| log_x / 10f64.log2()) }
#[pyfunction] fn pow(x: ArgIntoFloat, y: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> { let x = x.into_float(); let y = y.into_float();
if x < 0.0 && x.is_finite() && y.fract() != 0.0 && y.is_finite() || x == 0.0 && y < 0.0 && y != f64::NEG_INFINITY { return Err(vm.new_value_error("math domain error")); }
let value = x.powf(y);
if x.is_finite() && y.is_finite() && value.is_infinite() { return Err(vm.new_overflow_error("math range error")); // Handle BigInt specially for large values (only for actual int type, not float) if let Some(i) = x.downcast_ref::<PyInt>() { return pymath::math::log10_bigint(i.as_bigint()).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error("expected a positive input".to_owned()), _ => pymath_exception(err, vm), }); }
Ok(value) let val = x.try_float(vm)?.to_f64(); pymath::math::log10(val).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error(format!( "expected a positive input, got {}", super::float_repr(val) )), _ => pymath_exception(err, vm), }) }
#[pyfunction] fn log1p(x: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> { let x = x.into_float(); if x.is_nan() || x > -1.0_f64 { Ok(x.ln_1p()) } else { Err(vm.new_value_error("math domain error")) } }
/// Generates the base-2 logarithm of a BigInt `x` fn int_log2(x: &BigInt) -> f64 { // log2(x) = log2(2^n * 2^-n * x) = n + log2(x/2^n) // If we set 2^n to be the greatest power of 2 below x, then x/2^n is in [1, 2), and can // thus be converted into a float. let n = x.bits() as u32 - 1; let frac = true_div(x, &BigInt::from(2).pow(n)); f64::from(n) + frac.log2() pymath::math::log1p(x.into_float()).map_err(|err| pymath_exception(err, vm)) }
#[pyfunction] fn log2(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> { match x.try_float(vm) { Ok(x) => { let x = x.to_f64(); if x.is_nan() || x > 0.0_f64 { Ok(x.log2()) } else { Err(vm.new_value_error("math domain error")) } } Err(float_err) => { if let Ok(x) = x.try_int(vm) { let x = x.as_bigint(); if x.is_positive() { Ok(int_log2(x)) } else { Err(vm.new_value_error("math domain error")) } } else { // Return the float error, as it will be more intuitive to users Err(float_err) } } // Handle BigInt specially for large values (only for actual int type, not float) if let Some(i) = x.downcast_ref::<PyInt>() { return pymath::math::log2_bigint(i.as_bigint()).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error("expected a positive input".to_owned()), _ => pymath_exception(err, vm), }); } let val = x.try_float(vm)?.to_f64(); pymath::math::log2(val).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error(format!( "expected a positive input, got {}", super::float_repr(val) )), _ => pymath_exception(err, vm), }) }
#[pyfunction] fn log10(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> { log2(x, vm).map(|log_x| log_x / 10f64.log2()) }
#[pyfunction] fn pow(x: ArgIntoFloat, y: ArgIntoFloat, vm: &VirtualMachine) -> PyResult<f64> { let x = x.into_float(); let y = y.into_float();
if x < 0.0 && x.is_finite() && y.fract() != 0.0 && y.is_finite() || x == 0.0 && y < 0.0 && y != f64::NEG_INFINITY { return Err(vm.new_value_error("math domain error")); }
let value = x.powf(y);
if x.is_finite() && y.is_finite() && value.is_infinite() { return Err(vm.new_overflow_error("math range error")); // Handle BigInt specially for large values (only for actual int type, not float) if let Some(i) = x.downcast_ref::<PyInt>() { return pymath::math::log10_bigint(i.as_bigint()).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error("expected a positive input".to_owned()), _ => pymath_exception(err, vm), }); }
Ok(value) let val = x.try_float(vm)?.to_f64(); pymath::math::log10(val).map_err(|err| match err { pymath::Error::EDOM => vm.new_value_error(format!( "expected a positive input, got {}", super::float_repr(val) )), _ => pymath_exception(err, vm), }) }