Skip to content

Commit adb7096

Browse files
committed
fix powi
1 parent 4a405df commit adb7096

File tree

3 files changed

+51
-44
lines changed

3 files changed

+51
-44
lines changed

src/float/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod sub;
1515
#[doc(hidden)]
1616
pub trait Float:
1717
Copy
18+
+ core::fmt::Debug
1819
+ PartialEq
1920
+ PartialOrd
2021
+ ops::AddAssign

src/float/pow.rs

+22-25
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,36 @@
11
use float::Float;
2+
use int::Int;
23

3-
trait Pow: Float {
4-
/// Returns `a` raised to the power `b`
5-
fn pow(self, mut b: i32) -> Self {
6-
let mut a = self;
7-
let recip = b < 0;
8-
let mut r = Self::ONE;
9-
loop {
10-
if (b & 1) != 0 {
11-
r *= a;
12-
}
13-
b = ((b as u32) >> 1) as i32;
14-
if b == 0 {
15-
break;
16-
}
17-
a *= a;
4+
/// Returns `a` raised to the power `b`
5+
fn pow<F: Float>(a: F, b: i32) -> F {
6+
let mut a = a;
7+
let recip = b < 0;
8+
let mut pow = i32::abs_diff(b, 0);
9+
let mut mul = F::ONE;
10+
loop {
11+
if (pow & 1) != 0 {
12+
mul *= a;
1813
}
19-
20-
if recip {
21-
Self::ONE / r
22-
} else {
23-
r
14+
pow >>= 1;
15+
if pow == 0 {
16+
break;
2417
}
18+
a *= a;
2519
}
26-
}
2720

28-
impl Pow for f32 {}
29-
impl Pow for f64 {}
21+
if recip {
22+
F::ONE / mul
23+
} else {
24+
mul
25+
}
26+
}
3027

3128
intrinsics! {
3229
pub extern "C" fn __powisf2(a: f32, b: i32) -> f32 {
33-
a.pow(b)
30+
pow(a, b)
3431
}
3532

3633
pub extern "C" fn __powidf2(a: f64, b: i32) -> f64 {
37-
a.pow(b)
34+
pow(a, b)
3835
}
3936
}

testcrate/tests/misc.rs

+28-19
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,39 @@ fn float_extend_arm() {
126126
extend!(f32, f64, __extendsfdf2vfp);
127127
}
128128

129-
// This doesn't quite work because of issues related to
129+
// This is approximate because of issues related to
130130
// https://github.com/rust-lang/rust/issues/73920.
131-
// TODO how do we resolve this?
132-
/*
131+
// TODO how do we resolve this indeterminacy?
133132
macro_rules! pow {
134-
($($f:ty, $fn:ident);*;) => {
133+
($($f:ty, $tolerance:expr, $fn:ident);*;) => {
135134
$(
136135
fuzz_float_2(N, |x: $f, y: $f| {
137-
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x < 0. || y < 0.) {
138-
let n = y as i32;
136+
if !(Float::is_subnormal(x) || Float::is_subnormal(y) || x.is_nan()) {
137+
let n = y.to_bits() & !<$f as Float>::SIGNIFICAND_MASK;
138+
let n = (n as <$f as Float>::SignedInt) >> <$f as Float>::SIGNIFICAND_BITS;
139+
let n = n as i32;
139140
let tmp0: $f = x.powi(n);
140141
let tmp1: $f = $fn(x, n);
141-
if tmp0 != tmp1 {
142+
let (a, b) = if tmp0 < tmp1 {
143+
(tmp0, tmp1)
144+
} else {
145+
(tmp1, tmp0)
146+
};
147+
let good = {
148+
if a == b {
149+
// handles infinity equality
150+
true
151+
} else if a < $tolerance {
152+
b < $tolerance
153+
} else {
154+
let quo = b / a;
155+
(quo < (1. + $tolerance)) && (quo > (1. - $tolerance))
156+
}
157+
};
158+
if !good {
142159
panic!(
143160
"{}({}, {}): std: {}, builtins: {}",
144-
stringify!($fn), x, y, tmp0, tmp1
161+
stringify!($fn), x, n, tmp0, tmp1
145162
);
146163
}
147164
}
@@ -150,21 +167,13 @@ macro_rules! pow {
150167
};
151168
}
152169

170+
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
153171
#[test]
154172
fn float_pow() {
155173
use compiler_builtins::float::pow::{__powidf2, __powisf2};
156174

157175
pow!(
158-
f32, __powisf2;
159-
f64, __powidf2;
176+
f32, 1e-4, __powisf2;
177+
f64, 1e-12, __powidf2;
160178
);
161179
}
162-
*/
163-
164-
// placeholder test to make sure basic functionality works
165-
#[test]
166-
fn float_pow() {
167-
use compiler_builtins::float::pow::{__powidf2, __powisf2};
168-
assert_eq!(__powisf2(-3.0, 3), -27.0);
169-
assert_eq!(__powidf2(-3.0, 3), -27.0);
170-
}

0 commit comments

Comments
 (0)