Remove pow accuracy workaround

https://github.com/neogenie/fastnum/issues/28
This commit is contained in:
Kasper 2025-06-03 01:29:22 +02:00
parent f918f3d5e0
commit 9b49d8c418
No known key found for this signature in database
GPG Key ID: 3E47D7CD99820B85
3 changed files with 9 additions and 15 deletions

4
Cargo.lock generated
View File

@ -60,9 +60,9 @@ dependencies = [
[[package]] [[package]]
name = "fastnum" name = "fastnum"
version = "0.2.8" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86cde0c9334bfed5ced962bd7acc266e02e254d71494787e4255d8ec4f7296d4" checksum = "b875e26379edd7866a74cec720c6ae7bea3107aaf9fd3b14d7449d87d4c1986b"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bnum", "bnum",

View File

@ -299,6 +299,8 @@ mod tests {
assert_eq!(eval_default("-1km to m"), Number::new(d!(-1000), Unit::Meter)); assert_eq!(eval_default("-1km to m"), Number::new(d!(-1000), Unit::Meter));
assert_eq!(eval_num("2*-3*0.5"), "-3"); assert_eq!(eval_num("2*-3*0.5"), "-3");
assert_eq!(eval_num("-3^2"), "-9"); assert_eq!(eval_num("-3^2"), "-9");
assert_eq!(eval_num("e^2"), "7.3890560989306502272304274605750078132");
assert_eq!(eval_num("e^2.5"), "12.1824939607034734380701759511679661832");
assert_eq!(eval_num("-1+2"), "1"); assert_eq!(eval_num("-1+2"), "1");
} }

View File

@ -1,4 +1,4 @@
use fastnum::{dec128 as d, D128, D256}; use fastnum::{dec128 as d, D128};
use crate::Number; use crate::Number;
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
@ -754,15 +754,6 @@ pub fn modulo(left: Number, right: Number) -> Result<Number, String> {
} }
} }
fn do_pow(left: D128, right: D128) -> D128 {
// Do pow with d256 for higher accuracy
let left = D256::try_from(left.transmute()).unwrap();
let right = D256::try_from(right.transmute()).unwrap();
let result = left.pow(right);
let result_d128: D128 = result.transmute();
result_d128
}
/// Returns a [`Number`] to the power of another [`Number`] /// Returns a [`Number`] to the power of another [`Number`]
/// ///
/// - If you take [`Length`] to the power of [`NoType`], the result has a unit of [`Area`]. /// - If you take [`Length`] to the power of [`NoType`], the result has a unit of [`Area`].
@ -770,20 +761,21 @@ fn do_pow(left: D128, right: D128) -> D128 {
/// - If you take [`Length`] to the power of [`Area`], the result has a unit of [`Volume`] /// - If you take [`Length`] to the power of [`Area`], the result has a unit of [`Volume`]
/// - etc. /// - etc.
pub fn pow(left: Number, right: Number) -> Result<Number, String> { pub fn pow(left: Number, right: Number) -> Result<Number, String> {
// I tried converting `right` to use powi, but somehow that was slower
let lcat = left.unit.category(); let lcat = left.unit.category();
let rcat = left.unit.category(); let rcat = left.unit.category();
if left.unit == NoUnit && right.unit == NoUnit { if left.unit == NoUnit && right.unit == NoUnit {
// 3 ^ 2 // 3 ^ 2
Ok(Number::new(do_pow(left.value, right.value), left.unit)) Ok(Number::new(left.value.pow(right.value), left.unit))
} else if right.value == d!(1) && right.unit == NoUnit { } else if right.value == d!(1) && right.unit == NoUnit {
Ok(left) Ok(left)
} else if lcat == Length && right.unit == NoUnit && right.value == d!(2) { } else if lcat == Length && right.unit == NoUnit && right.value == d!(2) {
// x km ^ 2 // x km ^ 2
let result = do_pow(left.value * left.unit.weight(), right.value); let result = (left.value * left.unit.weight()).pow(right.value);
Ok(to_ideal_unit(Number::new(result, SquareMillimeter))) Ok(to_ideal_unit(Number::new(result, SquareMillimeter)))
} else if lcat == Length && right.unit == NoUnit && right.value == d!(3) { } else if lcat == Length && right.unit == NoUnit && right.value == d!(3) {
// x km ^ 3 // x km ^ 3
let result = do_pow(left.value * left.unit.weight(), right.value); let result = (left.value * left.unit.weight()).pow(right.value);
Ok(to_ideal_unit(Number::new(result, CubicMillimeter))) Ok(to_ideal_unit(Number::new(result, CubicMillimeter)))
} else if lcat == Length && rcat == Length && right.value == d!(1) { } else if lcat == Length && rcat == Length && right.value == d!(1) {
// x km ^ 1 km // x km ^ 1 km