fix powi
This commit is contained in:
@@ -15,6 +15,7 @@ pub mod sub;
|
||||
#[doc(hidden)]
|
||||
pub trait Float:
|
||||
Copy
|
||||
+ core::fmt::Debug
|
||||
+ PartialEq
|
||||
+ PartialOrd
|
||||
+ ops::AddAssign
|
||||
|
||||
@@ -1,39 +1,36 @@
|
||||
use float::Float;
|
||||
use int::Int;
|
||||
|
||||
trait Pow: Float {
|
||||
/// Returns `a` raised to the power `b`
|
||||
fn pow(self, mut b: i32) -> Self {
|
||||
let mut a = self;
|
||||
fn pow<F: Float>(a: F, b: i32) -> F {
|
||||
let mut a = a;
|
||||
let recip = b < 0;
|
||||
let mut r = Self::ONE;
|
||||
let mut pow = i32::abs_diff(b, 0);
|
||||
let mut mul = F::ONE;
|
||||
loop {
|
||||
if (b & 1) != 0 {
|
||||
r *= a;
|
||||
if (pow & 1) != 0 {
|
||||
mul *= a;
|
||||
}
|
||||
b = ((b as u32) >> 1) as i32;
|
||||
if b == 0 {
|
||||
pow >>= 1;
|
||||
if pow == 0 {
|
||||
break;
|
||||
}
|
||||
a *= a;
|
||||
}
|
||||
|
||||
if recip {
|
||||
Self::ONE / r
|
||||
F::ONE / mul
|
||||
} else {
|
||||
r
|
||||
mul
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pow for f32 {}
|
||||
impl Pow for f64 {}
|
||||
|
||||
intrinsics! {
|
||||
pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 {
|
||||
a.pow(b)
|
||||
pow(a, b)
|
||||
}
|
||||
|
||||
pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 {
|
||||
a.pow(b)
|
||||
pow(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,22 +126,39 @@ fn float_extend_arm() {
|
||||
extend!(f32, f64, __extendsfdf2vfp);
|
||||
}
|
||||
|
||||
// This doesn't quite work because of issues related to
|
||||
// This is approximate because of issues related to
|
||||
// https://github.com/rust-lang/rust/issues/73920.
|
||||
// TODO how do we resolve this?
|
||||
/*
|
||||
// TODO how do we resolve this indeterminacy?
|
||||
macro_rules! pow {
|
||||
($($f:ty, $fn:ident);*;) => {
|
||||
($($f:ty, $tolerance:expr, $fn:ident);*;) => {
|
||||
$(
|
||||
fuzz_float_2(N, |x: $f, y: $f| {
|
||||
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) {
|
||||
let n = y as i32;
|
||||
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
|
||||
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
|
||||
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
|
||||
let n = n as i32;
|
||||
let tmp0: $f = x.powi(n);
|
||||
let tmp1: $f = $fn(x, n);
|
||||
if tmp0 != tmp1 {
|
||||
let (a, b) = if tmp0 < tmp1 {
|
||||
(tmp0, tmp1)
|
||||
} else {
|
||||
(tmp1, tmp0)
|
||||
};
|
||||
let good = {
|
||||
if a == b {
|
||||
// handles infinity equality
|
||||
true
|
||||
} else if a < $tolerance {
|
||||
b < $tolerance
|
||||
} else {
|
||||
let quo = b / a;
|
||||
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
|
||||
}
|
||||
};
|
||||
if !good {
|
||||
panic!(
|
||||
"{}({}, {}): std: {}, builtins: {}",
|
||||
stringify!($fn), x, y, tmp0, tmp1
|
||||
stringify!($fn), x, n, tmp0, tmp1
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -150,21 +167,13 @@ macro_rules! pow {
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
|
||||
#[test]
|
||||
fn float_pow() {
|
||||
use compiler_builtins::float::pow::{__powidf2, __powisf2};
|
||||
|
||||
pow!(
|
||||
f32, __powisf2;
|
||||
f64, __powidf2;
|
||||
f32, 1e-4, __powisf2;
|
||||
f64, 1e-12, __powidf2;
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
// placeholder test to make sure basic functionality works
|
||||
#[test]
|
||||
fn float_pow() {
|
||||
use compiler_builtins::float::pow::{__powidf2, __powisf2};
|
||||
assert_eq!(__powisf2(-3.0, 3), -27.0);
|
||||
assert_eq!(__powidf2(-3.0, 3), -27.0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user