Skip to content

Commit 44cb46f

Browse files
committed
Add ldexp and frexp functions
1 parent 8d4d2b0 commit 44cb46f

File tree

4 files changed

+184
-1
lines changed

4 files changed

+184
-1
lines changed

src/libcore/num/f32.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
//! Operations and constants for `f32`
1212
13+
use libc::c_int;
1314
use num::{Zero, One, strconv};
1415
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
1516
use prelude::*;
@@ -672,6 +673,25 @@ impl Float for f32 {
672673
#[inline(always)]
673674
fn max_10_exp() -> int { 38 }
674675

676+
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
677+
#[inline(always)]
678+
fn ldexp(x: f32, exp: int) -> f32 {
679+
ldexp(x, exp as c_int)
680+
}
681+
682+
///
683+
/// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
684+
///
685+
/// - `self = x * pow(2, exp)`
686+
/// - `0.5 <= abs(x) < 1.0`
687+
///
688+
#[inline(always)]
689+
fn frexp(&self) -> (f32, int) {
690+
let mut exp = 0;
691+
let x = frexp(*self, &mut exp);
692+
(x, exp as int)
693+
}
694+
675695
///
676696
/// Returns the exponential of the number, minus `1`, in a way that is accurate
677697
/// even if the number is close to zero
@@ -1180,4 +1200,44 @@ mod tests {
11801200
assert_eq!(1e-37f32.classify(), FPNormal);
11811201
assert_eq!(1e-38f32.classify(), FPSubnormal);
11821202
}
1203+
1204+
#[test]
1205+
fn test_ldexp() {
1206+
// We have to use from_str until base-2 exponents
1207+
// are supported in floating-point literals
1208+
let f1: f32 = from_str_hex("1p-123").unwrap();
1209+
let f2: f32 = from_str_hex("1p-111").unwrap();
1210+
assert_eq!(Float::ldexp(1f32, -123), f1);
1211+
assert_eq!(Float::ldexp(1f32, -111), f2);
1212+
1213+
assert_eq!(Float::ldexp(0f32, -123), 0f32);
1214+
assert_eq!(Float::ldexp(-0f32, -123), -0f32);
1215+
assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123),
1216+
Float::infinity::<f32>());
1217+
assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123),
1218+
Float::neg_infinity::<f32>());
1219+
assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN());
1220+
}
1221+
1222+
#[test]
1223+
fn test_frexp() {
1224+
// We have to use from_str until base-2 exponents
1225+
// are supported in floating-point literals
1226+
let f1: f32 = from_str_hex("1p-123").unwrap();
1227+
let f2: f32 = from_str_hex("1p-111").unwrap();
1228+
let (x1, exp1) = f1.frexp();
1229+
let (x2, exp2) = f2.frexp();
1230+
assert_eq!((x1, exp1), (0.5f32, -122));
1231+
assert_eq!((x2, exp2), (0.5f32, -110));
1232+
assert_eq!(Float::ldexp(x1, exp1), f1);
1233+
assert_eq!(Float::ldexp(x2, exp2), f2);
1234+
1235+
assert_eq!(0f32.frexp(), (0f32, 0));
1236+
assert_eq!((-0f32).frexp(), (-0f32, 0));
1237+
assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x },
1238+
Float::infinity::<f32>())
1239+
assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x },
1240+
Float::neg_infinity::<f32>())
1241+
assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() })
1242+
}
11831243
}

src/libcore/num/f64.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,25 @@ impl Float for f64 {
715715
#[inline(always)]
716716
fn max_10_exp() -> int { 308 }
717717

718+
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
719+
#[inline(always)]
720+
fn ldexp(x: f64, exp: int) -> f64 {
721+
ldexp(x, exp as c_int)
722+
}
723+
724+
///
725+
/// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
726+
///
727+
/// - `self = x * pow(2, exp)`
728+
/// - `0.5 <= abs(x) < 1.0`
729+
///
730+
#[inline(always)]
731+
fn frexp(&self) -> (f64, int) {
732+
let mut exp = 0;
733+
let x = frexp(*self, &mut exp);
734+
(x, exp as int)
735+
}
736+
718737
///
719738
/// Returns the exponential of the number, minus `1`, in a way that is accurate
720739
/// even if the number is close to zero
@@ -1226,4 +1245,44 @@ mod tests {
12261245
assert_eq!(1e-307f64.classify(), FPNormal);
12271246
assert_eq!(1e-308f64.classify(), FPSubnormal);
12281247
}
1248+
1249+
#[test]
1250+
fn test_ldexp() {
1251+
// We have to use from_str until base-2 exponents
1252+
// are supported in floating-point literals
1253+
let f1: f64 = from_str_hex("1p-123").unwrap();
1254+
let f2: f64 = from_str_hex("1p-111").unwrap();
1255+
assert_eq!(Float::ldexp(1f64, -123), f1);
1256+
assert_eq!(Float::ldexp(1f64, -111), f2);
1257+
1258+
assert_eq!(Float::ldexp(0f64, -123), 0f64);
1259+
assert_eq!(Float::ldexp(-0f64, -123), -0f64);
1260+
assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123),
1261+
Float::infinity::<f64>());
1262+
assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123),
1263+
Float::neg_infinity::<f64>());
1264+
assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN());
1265+
}
1266+
1267+
#[test]
1268+
fn test_frexp() {
1269+
// We have to use from_str until base-2 exponents
1270+
// are supported in floating-point literals
1271+
let f1: f64 = from_str_hex("1p-123").unwrap();
1272+
let f2: f64 = from_str_hex("1p-111").unwrap();
1273+
let (x1, exp1) = f1.frexp();
1274+
let (x2, exp2) = f2.frexp();
1275+
assert_eq!((x1, exp1), (0.5f64, -122));
1276+
assert_eq!((x2, exp2), (0.5f64, -110));
1277+
assert_eq!(Float::ldexp(x1, exp1), f1);
1278+
assert_eq!(Float::ldexp(x2, exp2), f2);
1279+
1280+
assert_eq!(0f64.frexp(), (0f64, 0));
1281+
assert_eq!((-0f64).frexp(), (-0f64, 0));
1282+
assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x },
1283+
Float::infinity::<f64>())
1284+
assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x },
1285+
Float::neg_infinity::<f64>())
1286+
assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() })
1287+
}
12291288
}

src/libcore/num/float.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,25 @@ impl Float for float {
881881
#[inline(always)]
882882
fn max_10_exp() -> int { Float::max_10_exp::<f64>() }
883883
884+
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
885+
#[inline(always)]
886+
fn ldexp(x: float, exp: int) -> float {
887+
Float::ldexp(x as f64, exp) as float
888+
}
889+
890+
///
891+
/// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
892+
///
893+
/// - `self = x * pow(2, exp)`
894+
/// - `0.5 <= abs(x) < 1.0`
895+
///
896+
#[inline(always)]
897+
fn frexp(&self) -> (float, int) {
898+
match (*self as f64).frexp() {
899+
(x, exp) => (x as float, exp)
900+
}
901+
}
902+
884903
///
885904
/// Returns the exponential of the number, minus `1`, in a way that is accurate
886905
/// even if the number is close to zero
@@ -895,7 +914,9 @@ impl Float for float {
895914
/// than if the operations were performed separately
896915
///
897916
#[inline(always)]
898-
fn ln_1p(&self) -> float { (*self as f64).ln_1p() as float }
917+
fn ln_1p(&self) -> float {
918+
(*self as f64).ln_1p() as float
919+
}
899920
900921
///
901922
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
@@ -1174,6 +1195,46 @@ mod tests {
11741195
assert_eq!(1e-308f.classify(), FPSubnormal);
11751196
}
11761197
1198+
#[test]
1199+
fn test_ldexp() {
1200+
// We have to use from_str until base-2 exponents
1201+
// are supported in floating-point literals
1202+
let f1: float = from_str_hex("1p-123").unwrap();
1203+
let f2: float = from_str_hex("1p-111").unwrap();
1204+
assert_eq!(Float::ldexp(1f, -123), f1);
1205+
assert_eq!(Float::ldexp(1f, -111), f2);
1206+
1207+
assert_eq!(Float::ldexp(0f, -123), 0f);
1208+
assert_eq!(Float::ldexp(-0f, -123), -0f);
1209+
assert_eq!(Float::ldexp(Float::infinity::<float>(), -123),
1210+
Float::infinity::<float>());
1211+
assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123),
1212+
Float::neg_infinity::<float>());
1213+
assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN());
1214+
}
1215+
1216+
#[test]
1217+
fn test_frexp() {
1218+
// We have to use from_str until base-2 exponents
1219+
// are supported in floating-point literals
1220+
let f1: float = from_str_hex("1p-123").unwrap();
1221+
let f2: float = from_str_hex("1p-111").unwrap();
1222+
let (x1, exp1) = f1.frexp();
1223+
let (x2, exp2) = f2.frexp();
1224+
assert_eq!((x1, exp1), (0.5f, -122));
1225+
assert_eq!((x2, exp2), (0.5f, -110));
1226+
assert_eq!(Float::ldexp(x1, exp1), f1);
1227+
assert_eq!(Float::ldexp(x2, exp2), f2);
1228+
1229+
assert_eq!(0f.frexp(), (0f, 0));
1230+
assert_eq!((-0f).frexp(), (-0f, 0));
1231+
assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x },
1232+
Float::infinity::<float>())
1233+
assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x },
1234+
Float::neg_infinity::<float>())
1235+
assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() })
1236+
}
1237+
11771238
#[test]
11781239
pub fn test_to_str_exact_do_decimal() {
11791240
let s = to_str_exact(5.0, 4u);

src/libcore/num/num.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ pub trait Float: Real
284284
fn min_10_exp() -> int;
285285
fn max_10_exp() -> int;
286286

287+
fn ldexp(x: Self, exp: int) -> Self;
288+
fn frexp(&self) -> (Self, int);
289+
287290
fn exp_m1(&self) -> Self;
288291
fn ln_1p(&self) -> Self;
289292
fn mul_add(&self, a: Self, b: Self) -> Self;

0 commit comments

Comments
 (0)