This commit is contained in:
Aaron Kutch
2020-12-10 20:30:48 -06:00
parent 96a6110d69
commit 3871282eee
3 changed files with 51 additions and 44 deletions

View File

@@ -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

View File

@@ -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)
} }
} }

View File

@@ -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);
}