Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit ce116e9

Browse files
committed
Add a generic version of frexp and ilogb
This is used to replace `frexp`, `frexpf`, `ilogb`, and `ilogbf`.
1 parent 42a8dfb commit ce116e9

File tree

9 files changed

+81
-89
lines changed

9 files changed

+81
-89
lines changed

etc/function-definitions.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,13 +450,15 @@
450450
"frexp": {
451451
"sources": [
452452
"src/libm_helper.rs",
453-
"src/math/frexp.rs"
453+
"src/math/frexp.rs",
454+
"src/math/generic/frexp.rs"
454455
],
455456
"type": "f64"
456457
},
457458
"frexpf": {
458459
"sources": [
459-
"src/math/frexpf.rs"
460+
"src/math/frexpf.rs",
461+
"src/math/generic/frexp.rs"
460462
],
461463
"type": "f32"
462464
},
@@ -476,12 +478,14 @@
476478
"ilogb": {
477479
"sources": [
478480
"src/libm_helper.rs",
481+
"src/math/generic/ilogb.rs",
479482
"src/math/ilogb.rs"
480483
],
481484
"type": "f64"
482485
},
483486
"ilogbf": {
484487
"sources": [
488+
"src/math/generic/ilogb.rs",
485489
"src/math/ilogbf.rs"
486490
],
487491
"type": "f32"

src/math/frexp.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,7 @@
1+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
2+
///
3+
/// That is, `x * 2^p` will represent the input value.
4+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
15
pub fn frexp(x: f64) -> (f64, i32) {
2-
let mut y = x.to_bits();
3-
let ee = ((y >> 52) & 0x7ff) as i32;
4-
5-
if ee == 0 {
6-
if x != 0.0 {
7-
let x1p64 = f64::from_bits(0x43f0000000000000);
8-
let (x, e) = frexp(x * x1p64);
9-
return (x, e - 64);
10-
}
11-
return (x, 0);
12-
} else if ee == 0x7ff {
13-
return (x, 0);
14-
}
15-
16-
let e = ee - 0x3fe;
17-
y &= 0x800fffffffffffff;
18-
y |= 0x3fe0000000000000;
19-
return (f64::from_bits(y), e);
6+
super::generic::frexp(x)
207
}

src/math/frexpf.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,7 @@
1+
/// Decompose a float into a normalized value within the range `[0.5, 1)`, and a power of 2.
2+
///
3+
/// That is, `x * 2^p` will represent the input value.
4+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
15
pub fn frexpf(x: f32) -> (f32, i32) {
2-
let mut y = x.to_bits();
3-
let ee: i32 = ((y >> 23) & 0xff) as i32;
4-
5-
if ee == 0 {
6-
if x != 0.0 {
7-
let x1p64 = f32::from_bits(0x5f800000);
8-
let (x, e) = frexpf(x * x1p64);
9-
return (x, e - 64);
10-
} else {
11-
return (x, 0);
12-
}
13-
} else if ee == 0xff {
14-
return (x, 0);
15-
}
16-
17-
let e = ee - 0x7e;
18-
y &= 0x807fffff;
19-
y |= 0x3f000000;
20-
(f32::from_bits(y), e)
6+
super::generic::frexp(x)
217
}

src/math/generic/frexp.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use super::super::{CastFrom, Float, MinInt};
2+
3+
pub fn frexp<F: Float>(x: F) -> (F, i32) {
4+
let mut ix = x.to_bits();
5+
let ee = x.exp();
6+
7+
if ee == 0 {
8+
if x != F::ZERO {
9+
// normalize via multiplication; 1p64 for `f64`
10+
let magic = F::from_parts(false, F::EXP_BIAS + F::BITS, F::Int::ZERO);
11+
magic.to_bits();
12+
13+
let (x, e) = frexp(x * magic);
14+
return (x, e - F::BITS as i32);
15+
}
16+
return (x, 0);
17+
} else if ee == F::EXP_MAX {
18+
return (x, 0);
19+
}
20+
21+
let e = ee as i32 - (F::EXP_BIAS as i32 - 1);
22+
ix &= F::SIGN_MASK | F::SIG_MASK;
23+
ix |= F::Int::cast_from(F::EXP_BIAS - 1) << F::SIG_BITS;
24+
(F::from_bits(ix), e)
25+
}

src/math/generic/ilogb.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use super::super::{Float, MinInt};
2+
3+
const FP_ILOGBNAN: i32 = i32::MIN;
4+
const FP_ILOGB0: i32 = FP_ILOGBNAN;
5+
6+
pub fn ilogb<F: Float>(x: F) -> i32 {
7+
let zero = F::Int::ZERO;
8+
let mut i = x.to_bits();
9+
let e = x.exp() as i32;
10+
11+
if e == 0 {
12+
i <<= F::EXP_BITS + 1;
13+
if i == F::Int::ZERO {
14+
force_eval!(0.0 / 0.0);
15+
return FP_ILOGB0;
16+
}
17+
/* subnormal x */
18+
let mut e = -(F::EXP_BIAS as i32);
19+
while i >> (F::BITS - 1) == zero {
20+
e -= 1;
21+
i <<= 1;
22+
}
23+
e
24+
} else if e == F::EXP_MAX as i32 {
25+
force_eval!(0.0 / 0.0);
26+
if i << (F::EXP_BITS + 1) != zero { FP_ILOGBNAN } else { i32::MAX }
27+
} else {
28+
e - F::EXP_BIAS as i32
29+
}
30+
}

src/math/generic/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ mod fdim;
55
mod floor;
66
mod fmax;
77
mod fmin;
8+
mod frexp;
9+
mod ilogb;
810
mod rint;
911
mod round;
1012
mod scalbn;
@@ -18,6 +20,8 @@ pub use fdim::fdim;
1820
pub use floor::floor;
1921
pub use fmax::fmax;
2022
pub use fmin::fmin;
23+
pub use frexp::frexp;
24+
pub use ilogb::ilogb;
2125
pub use rint::rint;
2226
pub use round::round;
2327
pub use scalbn::scalbn;

src/math/ilogb.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
1-
const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
2-
const FP_ILOGB0: i32 = FP_ILOGBNAN;
3-
1+
/// Extract the binary exponent of `x`.
42
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
53
pub fn ilogb(x: f64) -> i32 {
6-
let mut i: u64 = x.to_bits();
7-
let e = ((i >> 52) & 0x7ff) as i32;
8-
9-
if e == 0 {
10-
i <<= 12;
11-
if i == 0 {
12-
force_eval!(0.0 / 0.0);
13-
return FP_ILOGB0;
14-
}
15-
/* subnormal x */
16-
let mut e = -0x3ff;
17-
while (i >> 63) == 0 {
18-
e -= 1;
19-
i <<= 1;
20-
}
21-
e
22-
} else if e == 0x7ff {
23-
force_eval!(0.0 / 0.0);
24-
if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX }
25-
} else {
26-
e - 0x3ff
27-
}
4+
super::generic::ilogb(x)
285
}

src/math/ilogbf.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
1-
const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
2-
const FP_ILOGB0: i32 = FP_ILOGBNAN;
3-
1+
/// Extract the binary exponent of `x`.
42
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
53
pub fn ilogbf(x: f32) -> i32 {
6-
let mut i = x.to_bits();
7-
let e = ((i >> 23) & 0xff) as i32;
8-
9-
if e == 0 {
10-
i <<= 9;
11-
if i == 0 {
12-
force_eval!(0.0 / 0.0);
13-
return FP_ILOGB0;
14-
}
15-
/* subnormal x */
16-
let mut e = -0x7f;
17-
while (i >> 31) == 0 {
18-
e -= 1;
19-
i <<= 1;
20-
}
21-
e
22-
} else if e == 0xff {
23-
force_eval!(0.0 / 0.0);
24-
if (i << 9) != 0 { FP_ILOGBNAN } else { i32::MAX }
25-
} else {
26-
e - 0x7f
27-
}
4+
super::generic::ilogb(x)
285
}

src/math/support/int_traits.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub trait Int:
4545
+ ops::BitOrAssign
4646
+ ops::BitXorAssign
4747
+ ops::ShlAssign<i32>
48+
+ ops::ShlAssign<u32>
49+
+ ops::ShrAssign<i32>
4850
+ ops::ShrAssign<u32>
4951
+ ops::Add<Output = Self>
5052
+ ops::Sub<Output = Self>

0 commit comments

Comments
 (0)