From 8908aad9881eac828c46aa7264962bb409119c19 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Aug 2018 02:47:49 -0400 Subject: [PATCH] Sync to ulfjack/ryu@46f4c55 --- README.md | 2 +- src/d2s.rs | 82 +++++++++++++++++++++++++++++-------------- src/d2s_intrinsics.rs | 22 ++++++++++++ src/lib.rs | 1 - 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index e1e9d31..93727f8 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ example `0.3` rather than `3E-1`. uses nothing from the Rust standard library so is usable from no_std crates.* [paper]: https://dl.acm.org/citation.cfm?id=3192369 -[upstream]: https://github.com/ulfjack/ryu/tree/a7641807758cffd19d95221708bd6baf6715dcb7 +[upstream]: https://github.com/ulfjack/ryu/tree/46f4c5572121a6f1428749fe3e24132c3626c946 ```toml [dependencies] diff --git a/src/d2s.rs b/src/d2s.rs index 4929990..0d42299 100644 --- a/src/d2s.rs +++ b/src/d2s.rs @@ -26,7 +26,6 @@ use d2s_full_table::*; #[cfg(feature = "small")] use d2s_small_table::*; use digit_table::*; -#[cfg(not(integer128))] use d2s_intrinsics::*; #[cfg(feature = "no-panic")] @@ -43,8 +42,8 @@ fn pow5_factor(mut value: u64) -> u32 { let mut count = 0u32; loop { debug_assert!(value != 0); - let q = value / 5; - let r = value % 5; + let q = div5(value); + let r = (value - 5 * q) as u32; if r != 0 { break; } @@ -243,7 +242,8 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { // This should use q <= 22, but I think 21 is also safe. Smaller values // may still be safe, but it's more difficult to reason about them. // Only one of mp, mv, and mm can be a multiple of 5, if any. - if mv % 5 == 0 { + let mv_mod5 = (mv - 5 * div5(mv)) as u32; + if mv_mod5 == 0 { vr_is_trailing_zeros = multiple_of_power_of_5(mv, q); } else if accept_bounds { // Same as min(e2 + (~mm & 1), pow5_factor(mm)) >= q @@ -306,22 +306,38 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { // On average, we remove ~2 digits. let output = if vm_is_trailing_zeros || vr_is_trailing_zeros { // General case, which happens rarely (~0.7%). - while vp / 10 > vm / 10 { - vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0; + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vm_mod10 = (vm - 10 * vm_div10) as u32; + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; + vm_is_trailing_zeros &= vm_mod10 == 0; vr_is_trailing_zeros &= last_removed_digit == 0; - last_removed_digit = (vr % 10) as u8; - vr /= 10; - vp /= 10; - vm /= 10; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; removed += 1; } if vm_is_trailing_zeros { - while vm % 10 == 0 { + loop { + let vm_div10 = div10(vm); + let vm_mod10 = (vm - 10 * vm_div10) as u32; + if vm_mod10 != 0 { + break; + } + let vp_div10 = div10(vp); + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; vr_is_trailing_zeros &= last_removed_digit == 0; - last_removed_digit = (vr % 10) as u8; - vr /= 10; - vp /= 10; - vm /= 10; + last_removed_digit = vr_mod10 as u8; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; removed += 1; } } @@ -335,23 +351,34 @@ pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 { } else { // Specialized for the common case (~99.3%). Percentages below are relative to this. let mut round_up = false; + let vp_div100 = div100(vp); + let vm_div100 = div100(vm); // Optimization: remove two digits at a time (~86.2%). - if vp / 100 > vm / 100 { - round_up = vr % 100 >= 50; - vr /= 100; - vp /= 100; - vm /= 100; + if vp_div100 > vm_div100 { + let vr_div100 = div100(vr); + let vr_mod100 = (vr - 100 * vr_div100) as u32; + round_up = vr_mod100 >= 50; + vr = vr_div100; + vp = vp_div100; + vm = vm_div100; removed += 2; } // Loop iterations below (approximately), without optimization above: // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02% // Loop iterations below (approximately), with optimization above: // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02% - while vp / 10 > vm / 10 { - round_up = vr % 10 >= 5; - vr /= 10; - vp /= 10; - vm /= 10; + loop { + let vp_div10 = div10(vp); + let vm_div10 = div10(vm); + if vp_div10 <= vm_div10 { + break; + } + let vr_div10 = div10(vr); + let vr_mod10 = (vr - 10 * vr_div10) as u32; + round_up = vr_mod10 >= 5; + vr = vr_div10; + vp = vp_div10; + vm = vm_div10; removed += 1; } // We need to take vr + 1 if vr is outside bounds or we need to round up. @@ -392,8 +419,9 @@ unsafe fn to_chars(v: FloatingDecimal64, sign: bool, result: *mut u8) -> usize { // so the rest will fit into uint32_t. if (output >> 32) != 0 { // Expensive 64-bit division. - let mut output2 = (output - 100000000 * (output / 100000000)) as u32; - output /= 100000000; + let q = div100_000_000(output); + let mut output2 = (output - 100_000_000 * q) as u32; + output = q; let c = output2 % 10000; output2 /= 10000; diff --git a/src/d2s_intrinsics.rs b/src/d2s_intrinsics.rs index 2112245..e0e280c 100644 --- a/src/d2s_intrinsics.rs +++ b/src/d2s_intrinsics.rs @@ -19,6 +19,7 @@ // KIND, either express or implied. // Returns (lo, hi). +#[cfg(not(integer128))] #[cfg_attr(feature = "no-panic", inline)] pub fn umul128(a: u64, b: u64) -> (u64, u64) { let a_lo = a as u32; @@ -48,6 +49,7 @@ pub fn umul128(a: u64, b: u64) -> (u64, u64) { (p_lo, p_hi) } +#[cfg(not(integer128))] #[cfg_attr(feature = "no-panic", inline)] pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { // We don't need to handle the case dist >= 64 here (see above). @@ -55,3 +57,23 @@ pub fn shiftright128(lo: u64, hi: u64, dist: u32) -> u64 { debug_assert!(dist < 64); (hi << (64 - dist)) | (lo >> dist) } + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div5(x: u64) -> u64 { + x / 5 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div10(x: u64) -> u64 { + x / 10 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div100(x: u64) -> u64 { + x / 100 +} + +#[cfg_attr(feature = "no-panic", inline)] +pub fn div100_000_000(x: u64) -> u64 { + x / 100_000_000 +} diff --git a/src/lib.rs b/src/lib.rs index 5a834fb..b9012ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,6 @@ mod common; mod d2s; #[cfg(not(feature = "small"))] mod d2s_full_table; -#[cfg(not(integer128))] mod d2s_intrinsics; #[cfg(feature = "small")] mod d2s_small_table;