Skip to content

Commit 2fa5337

Browse files
committed
Increase precision when converting to f64 #83
1 parent c379d33 commit 2fa5337

File tree

2 files changed

+40
-34
lines changed

2 files changed

+40
-34
lines changed

src/number.rs

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -209,55 +209,56 @@ impl fmt::Display for Number {
209209
}
210210
}
211211

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

219-
static NEG_POWERS: [f64; 23] = [
220-
1.0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7,
221-
1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15,
222-
1e-16, 1e-17, 1e-18, 1e-19, 1e-20, 1e-21, 1e-22
223-
];
224-
225-
let index = e.abs() as usize;
219+
if e >= 0 {
220+
let index = e as usize;
226221

227-
if index < 23 {
228-
if e < 0 {
229-
NEG_POWERS[index]
222+
n * if index < 23 {
223+
CACHE_POWERS[index]
230224
} else {
231-
POS_POWERS[index]
225+
10f64.powf(index as f64)
232226
}
233227
} else {
234-
// powf is more accurate
235-
10f64.powf(e as f64)
228+
let index = -e as usize;
229+
230+
n / if index < 23 {
231+
CACHE_POWERS[index]
232+
} else {
233+
10f64.powf(index as f64)
234+
}
236235
}
237236
}
238237

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

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

250-
let index = e.abs() as usize;
246+
if e >= 0 {
247+
let index = e as usize;
251248

252-
if index < 16 {
253-
if e < 0 {
254-
NEG_POWERS[index]
249+
n * if index < 23 {
250+
CACHE_POWERS[index]
255251
} else {
256-
POS_POWERS[index]
252+
10f32.powf(index as f32)
257253
}
258254
} else {
259-
// powf is more accurate
260-
10f32.powf(e as f32)
255+
let index = -e as usize;
256+
257+
n / if index < 23 {
258+
CACHE_POWERS[index]
259+
} else {
260+
10f32.powf(index as f32)
261+
}
261262
}
262263
}
263264

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

271272
if e < -308 {
272-
n *= exponent_to_power_f64(e + 308);
273+
n = exponentiate_f64(n, e + 308);
273274
e = -308;
274275
}
275276

276-
let f = n * exponent_to_power_f64(e);
277+
let f = exponentiate_f64(n, e);
277278
if num.is_sign_positive() { f } else { -f }
278279
}
279280
}
@@ -286,11 +287,11 @@ impl From<Number> for f32 {
286287
let mut e = num.exponent;
287288

288289
if e < -127 {
289-
n *= exponent_to_power_f32(e + 127);
290+
n = exponentiate_f32(n, e + 127);
290291
e = -127;
291292
}
292293

293-
let f = n * exponent_to_power_f32(e);
294+
let f = exponentiate_f32(n, e);
294295
if num.is_sign_positive() { f } else { -f }
295296
}
296297
}

tests/number.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,8 @@ fn as_fixed_point_i64() {
121121
assert_eq!(Number::from(-1).as_fixed_point_i64(0), Some(-1));
122122
assert_eq!(Number::from(f64::NAN).as_fixed_point_i64(0), None);
123123
}
124+
125+
#[test]
126+
fn convert_f64_precision() {
127+
assert_eq!(Number::from_parts(true, 4750000000000001, -18), 0.004750000000000001);
128+
}

0 commit comments

Comments
 (0)