fix powi
This commit is contained in:
@@ -15,6 +15,7 @@ pub mod sub;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait Float:
|
pub trait Float:
|
||||||
Copy
|
Copy
|
||||||
|
+ core::fmt::Debug
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ PartialOrd
|
+ PartialOrd
|
||||||
+ ops::AddAssign
|
+ ops::AddAssign
|
||||||
|
|||||||
@@ -1,39 +1,36 @@
|
|||||||
use float::Float;
|
use float::Float;
|
||||||
|
use int::Int;
|
||||||
|
|
||||||
trait Pow: Float {
|
|
||||||
/// Returns `a` raised to the power `b`
|
/// Returns `a` raised to the power `b`
|
||||||
fn pow(self, mut b: i32) -> Self {
|
fn pow<F: Float>(a: F, b: i32) -> F {
|
||||||
let mut a = self;
|
let mut a = a;
|
||||||
let recip = b < 0;
|
let recip = b < 0;
|
||||||
let mut r = Self::ONE;
|
let mut pow = i32::abs_diff(b, 0);
|
||||||
|
let mut mul = F::ONE;
|
||||||
loop {
|
loop {
|
||||||
if (b & 1) != 0 {
|
if (pow & 1) != 0 {
|
||||||
r *= a;
|
mul *= a;
|
||||||
}
|
}
|
||||||
b = ((b as u32) >> 1) as i32;
|
pow >>= 1;
|
||||||
if b == 0 {
|
if pow == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
a *= a;
|
a *= a;
|
||||||
}
|
}
|
||||||
|
|
||||||
if recip {
|
if recip {
|
||||||
Self::ONE / r
|
F::ONE / mul
|
||||||
} else {
|
} else {
|
||||||
r
|
mul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Pow for f32 {}
|
|
||||||
impl Pow for f64 {}
|
|
||||||
|
|
||||||
intrinsics! {
|
intrinsics! {
|
||||||
pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 {
|
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 {
|
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);
|
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.
|
// https://github.com/rust-lang/rust/issues/73920.
|
||||||
// TODO how do we resolve this?
|
// TODO how do we resolve this indeterminacy?
|
||||||
/*
|
|
||||||
macro_rules! pow {
|
macro_rules! pow {
|
||||||
($($f:ty, $fn:ident);*;) => {
|
($($f:ty, $tolerance:expr, $fn:ident);*;) => {
|
||||||
$(
|
$(
|
||||||
fuzz_float_2(N, |x: $f, y: $f| {
|
fuzz_float_2(N, |x: $f, y: $f| {
|
||||||
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) {
|
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
|
||||||
let n = y as i32;
|
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 tmp0: $f = x.powi(n);
|
||||||
let tmp1: $f = $fn(x, 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!(
|
panic!(
|
||||||
"{}({}, {}): std: {}, builtins: {}",
|
"{}({}, {}): 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]
|
#[test]
|
||||||
fn float_pow() {
|
fn float_pow() {
|
||||||
use compiler_builtins::float::pow::{__powidf2, __powisf2};
|
use compiler_builtins::float::pow::{__powidf2, __powisf2};
|
||||||
|
|
||||||
pow!(
|
pow!(
|
||||||
f32, __powisf2;
|
f32, 1e-4, __powisf2;
|
||||||
f64, __powidf2;
|
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