about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/core/benches/num/flt2dec/strategy/grisu.rs27
-rw-r--r--library/core/src/num/flt2dec/strategy/grisu.rs16
2 files changed, 43 insertions, 0 deletions
diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs
index 6bea5e55d37..17d6b474ad2 100644
--- a/library/core/benches/num/flt2dec/strategy/grisu.rs
+++ b/library/core/benches/num/flt2dec/strategy/grisu.rs
@@ -81,3 +81,30 @@ fn bench_big_exact_inf(b: &mut Bencher) {
         format_exact(black_box(&decoded), &mut buf, i16::MIN);
     });
 }
+
+#[bench]
+fn bench_one_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(1.0);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
+
+#[bench]
+fn bench_trailing_zero_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(250.000000000000000000000000);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
+
+#[bench]
+fn bench_halfway_point_exact_inf(b: &mut Bencher) {
+    let decoded = decode_finite(1.00000000000000011102230246251565404236316680908203125);
+    let mut buf = [MaybeUninit::new(0); 1024];
+    b.iter(|| {
+        format_exact(black_box(&decoded), &mut buf, i16::MIN);
+    });
+}
diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs
index ed3e0edaff2..b9f0d114c6a 100644
--- a/library/core/src/num/flt2dec/strategy/grisu.rs
+++ b/library/core/src/num/flt2dec/strategy/grisu.rs
@@ -487,6 +487,22 @@ pub fn format_exact_opt<'a>(
     let vint = (v.f >> e) as u32;
     let vfrac = v.f & ((1 << e) - 1);
 
+    let requested_digits = buf.len();
+
+    const POW10_UP_TO_9: [u32; 10] =
+        [1, 10, 100, 1000, 10_000, 100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000];
+
+    // We deviate from the original algorithm here and do some early checks to determine if we can satisfy requested_digits.
+    // If we determine that we can't, we exit early and avoid most of the heavy lifting that the algorithm otherwise does.
+    //
+    // When vfrac is zero, we can easily determine if vint can satisfy requested digits:
+    //      If requested_digits >= 11, vint is not able to exhaust the count by itself since 10^(11 -1) > u32 max value >= vint.
+    //      If vint < 10^(requested_digits - 1), vint cannot exhaust the count.
+    //      Otherwise, vint might be able to exhaust the count and we need to execute the rest of the code.
+    if (vfrac == 0) && ((requested_digits >= 11) || (vint < POW10_UP_TO_9[requested_digits - 1])) {
+        return None;
+    }
+
     // both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1).
     // as we don't know the error is positive or negative, we use two approximations
     // spaced equally and have the maximal error of 2 ulps (same to the shortest case).