about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorRobin Kruppe <robin.kruppe@gmail.com>2015-12-30 14:01:42 +0100
committerRobin Kruppe <robin.kruppe@gmail.com>2016-01-12 22:25:16 +0100
commitdad1df6c1ab8fa06e9c5a28a6849e61fcdaa5008 (patch)
tree9308db8fdb5edc8f61960a41f7e74f43fb7d03e6 /src/libcore
parent27a1834ce522e3ec7fe4726b1661de16ee30c503 (diff)
Speed up dec2flt fast path with additional tables.
Add tables of small powers of ten used in the fast path. The tables are redundant: We could also use the big, more accurate table and round the value to the correct type (in fact we did just that before this commit). However, the rounding is extra work and slows down the fast path.

Because only very small exponents enter the fast path, the table and thus the space overhead is negligible. Speed-wise, this is a clear win on a [benchmark] comparing the fast path to a naive, hand-optimized, inaccurate algorithm. Specifically, this change narrows the gap from a roughly 5x difference to a roughly 3.4x difference.

[benchmark]: https://gist.github.com/Veedrac/dbb0c07994bc7882098e
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/num/dec2flt/algorithm.rs10
-rw-r--r--src/libcore/num/dec2flt/rawfp.rs12
-rw-r--r--src/libcore/num/dec2flt/table.rs46
3 files changed, 59 insertions, 9 deletions
diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs
index 1f0f06d7461..82d3389edc4 100644
--- a/src/libcore/num/dec2flt/algorithm.rs
+++ b/src/libcore/num/dec2flt/algorithm.rs
@@ -60,17 +60,13 @@ pub fn fast_path<T: RawFloat>(integral: &[u8], fractional: &[u8], e: i64) -> Opt
     if f > T::max_sig() {
         return None;
     }
-    let e = e as i16; // Can't overflow because e.abs() <= LOG5_OF_EXP_N
     // The case e < 0 cannot be folded into the other branch. Negative powers result in
     // a repeating fractional part in binary, which are rounded, which causes real
     // (and occasioally quite significant!) errors in the final result.
-    // The case `e == 0`, however, is unnecessary for correctness. It's just measurably faster.
-    if e == 0 {
-        Some(T::from_int(f))
-    } else if e > 0 {
-        Some(T::from_int(f) * fp_to_float(power_of_ten(e)))
+    if e >= 0 {
+        Some(T::from_int(f) * T::short_fast_pow10(e as usize))
     } else {
-        Some(T::from_int(f) / fp_to_float(power_of_ten(-e)))
+        Some(T::from_int(f) / T::short_fast_pow10(e.abs() as usize))
     }
 }
 
diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs
index 19758974003..2099c6a7baa 100644
--- a/src/libcore/num/dec2flt/rawfp.rs
+++ b/src/libcore/num/dec2flt/rawfp.rs
@@ -37,6 +37,7 @@ use num::diy_float::Fp;
 use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
 use num::Float;
 use num::dec2flt::num::{self, Big};
+use num::dec2flt::table;
 
 #[derive(Copy, Clone, Debug)]
 pub struct Unpacked {
@@ -73,6 +74,9 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     /// represented, the other code in this module makes sure to never let that happen.
     fn from_int(x: u64) -> Self;
 
+    /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig().
+    fn short_fast_pow10(e: usize) -> Self;
+
     // FIXME Everything that follows should be associated constants, but taking the value of an
     // associated constant from a type parameter does not work (yet?)
     // A possible workaround is having a `FloatInfo` struct for all the constants, but so far
@@ -175,6 +179,10 @@ impl RawFloat for f32 {
         x as f32
     }
 
+    fn short_fast_pow10(e: usize) -> Self {
+        table::F32_SHORT_POWERS[e]
+    }
+
     fn max_normal_digits() -> usize {
         35
     }
@@ -222,6 +230,10 @@ impl RawFloat for f64 {
         x as f64
     }
 
+    fn short_fast_pow10(e: usize) -> Self {
+        table::F64_SHORT_POWERS[e]
+    }
+
     fn max_normal_digits() -> usize {
         305
     }
diff --git a/src/libcore/num/dec2flt/table.rs b/src/libcore/num/dec2flt/table.rs
index dd985fd155b..cb8c94313d0 100644
--- a/src/libcore/num/dec2flt/table.rs
+++ b/src/libcore/num/dec2flt/table.rs
@@ -7,8 +7,10 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-// Table of approximations of powers of ten.
-// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py
+
+//! Tables of approximations of powers of ten.
+//! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py`
+
 pub const MIN_E: i16 = -305;
 pub const MAX_E: i16 = 305;
 
@@ -1237,3 +1239,43 @@ pub const POWERS: ([u64; 611], [i16; 611]) = ([
     946,
     950,
 ]);
+
+pub const F32_SHORT_POWERS: [f32; 11] = [
+    1e0,
+    1e1,
+    1e2,
+    1e3,
+    1e4,
+    1e5,
+    1e6,
+    1e7,
+    1e8,
+    1e9,
+    1e10,
+];
+
+pub const F64_SHORT_POWERS: [f64; 23] = [
+    1e0,
+    1e1,
+    1e2,
+    1e3,
+    1e4,
+    1e5,
+    1e6,
+    1e7,
+    1e8,
+    1e9,
+    1e10,
+    1e11,
+    1e12,
+    1e13,
+    1e14,
+    1e15,
+    1e16,
+    1e17,
+    1e18,
+    1e19,
+    1e20,
+    1e21,
+    1e22,
+];