Skip to content

Commit

Permalink
Increase precision when converting to f64 #83
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejhirsz committed Aug 1, 2016
1 parent c379d33 commit 2fa5337
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 34 deletions.
69 changes: 35 additions & 34 deletions src/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,55 +209,56 @@ impl fmt::Display for Number {
}
}

fn exponent_to_power_f64(e: i16) -> f64 {
static POS_POWERS: [f64; 23] = [
fn exponentiate_f64(n: f64, e: i16) -> f64 {
static CACHE_POWERS: [f64; 23] = [
1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
];

static NEG_POWERS: [f64; 23] = [
1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7,
1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15,
1e-16, 1e-17, 1e-18, 1e-19, 1e-20, 1e-21, 1e-22
];

let index = e.abs() as usize;
if e >= 0 {
let index = e as usize;

if index < 23 {
if e < 0 {
NEG_POWERS[index]
n * if index < 23 {
CACHE_POWERS[index]
} else {
POS_POWERS[index]
10f64.powf(index as f64)
}
} else {
// powf is more accurate
10f64.powf(e as f64)
let index = -e as usize;

n / if index < 23 {
CACHE_POWERS[index]
} else {
10f64.powf(index as f64)
}
}
}

fn exponent_to_power_f32(e: i16) -> f32 {
static POS_POWERS: [f32; 16] = [
1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15
];

static NEG_POWERS: [f32; 16] = [
1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7,
1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15
fn exponentiate_f32(n: f32, e: i16) -> f32 {
static CACHE_POWERS: [f32; 23] = [
1.0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
];

let index = e.abs() as usize;
if e >= 0 {
let index = e as usize;

if index < 16 {
if e < 0 {
NEG_POWERS[index]
n * if index < 23 {
CACHE_POWERS[index]
} else {
POS_POWERS[index]
10f32.powf(index as f32)
}
} else {
// powf is more accurate
10f32.powf(e as f32)
let index = -e as usize;

n / if index < 23 {
CACHE_POWERS[index]
} else {
10f32.powf(index as f32)
}
}
}

Expand All @@ -269,11 +270,11 @@ impl From<Number> for f64 {
let mut e = num.exponent;

if e < -308 {
n *= exponent_to_power_f64(e + 308);
n = exponentiate_f64(n, e + 308);
e = -308;
}

let f = n * exponent_to_power_f64(e);
let f = exponentiate_f64(n, e);
if num.is_sign_positive() { f } else { -f }
}
}
Expand All @@ -286,11 +287,11 @@ impl From<Number> for f32 {
let mut e = num.exponent;

if e < -127 {
n *= exponent_to_power_f32(e + 127);
n = exponentiate_f32(n, e + 127);
e = -127;
}

let f = n * exponent_to_power_f32(e);
let f = exponentiate_f32(n, e);
if num.is_sign_positive() { f } else { -f }
}
}
Expand Down
5 changes: 5 additions & 0 deletions tests/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,8 @@ fn as_fixed_point_i64() {
assert_eq!(Number::from(-1).as_fixed_point_i64(0), Some(-1));
assert_eq!(Number::from(f64::NAN).as_fixed_point_i64(0), None);
}

#[test]
fn convert_f64_precision() {
assert_eq!(Number::from_parts(true, 4750000000000001, -18), 0.004750000000000001);
}

0 comments on commit 2fa5337

Please sign in to comment.