Skip to content

Commit 83dd273

Browse files
committed
1 parent ecb1c4a commit 83dd273

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ numbers to decimal strings.
1111
This Rust implementation is a line-by-line port of Victor Zverovich's
1212
implementation in C++, [https://github.com/vitaut/zmij][upstream].
1313

14-
[upstream]: https://github.com/vitaut/zmij/tree/9a433c4bed034447c051e16b405ebc43cae05957
14+
[upstream]: https://github.com/vitaut/zmij/tree/f5c342697455b3a443ad4f331e35f4d74a7420b6
1515

1616
## Example
1717

src/lib.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ mod traits;
6868
#[cfg(not(zmij_no_select_unpredictable))]
6969
use core::hint;
7070
use core::mem::{self, MaybeUninit};
71+
#[cfg(test)]
72+
use core::ops::Index;
7173
use core::ptr;
7274
use core::slice;
7375
use core::str;
@@ -170,9 +172,27 @@ impl FloatTraits for f64 {
170172
}
171173
}
172174

175+
struct Pow10SignificandsTable([(u64, u64); 617]);
176+
177+
impl Pow10SignificandsTable {
178+
unsafe fn get_unchecked(&self, dec_exp: i32) -> &(u64, u64) {
179+
const DEC_EXP_MIN: i32 = -292;
180+
unsafe { self.0.get_unchecked((dec_exp - DEC_EXP_MIN) as usize) }
181+
}
182+
}
183+
184+
#[cfg(test)]
185+
impl Index<i32> for Pow10SignificandsTable {
186+
type Output = (u64, u64);
187+
fn index(&self, dec_exp: i32) -> &Self::Output {
188+
const DEC_EXP_MIN: i32 = -292;
189+
&self.0[(dec_exp - DEC_EXP_MIN) as usize]
190+
}
191+
}
192+
173193
// 128-bit significands of powers of 10 rounded down.
174194
// Generated using 192-bit arithmetic method by Dougall Johnson.
175-
static POW10_SIGNIFICANDS: [(u64, u64); 617] = {
195+
static POW10_SIGNIFICANDS: Pow10SignificandsTable = {
176196
let mut data = [(0, 0); 617];
177197

178198
struct uint192 {
@@ -218,11 +238,9 @@ static POW10_SIGNIFICANDS: [(u64, u64); 617] = {
218238
i += 1;
219239
}
220240

221-
data
241+
Pow10SignificandsTable(data)
222242
};
223243

224-
const DEC_EXP_MIN: i32 = -292;
225-
226244
#[cfg_attr(feature = "no-panic", no_panic)]
227245
fn count_trailing_nonzeros(x: u64) -> usize {
228246
// We count the number of bytes until there are only zeros left.
@@ -537,8 +555,7 @@ where
537555
let num_bits = mem::size_of::<UInt>() as i32 * 8;
538556
if regular && !subnormal {
539557
let exp_shift = compute_exp_shift(bin_exp, dec_exp);
540-
let (pow10_hi, pow10_lo) =
541-
*unsafe { POW10_SIGNIFICANDS.get_unchecked((-dec_exp - DEC_EXP_MIN) as usize) };
558+
let (pow10_hi, pow10_lo) = *unsafe { POW10_SIGNIFICANDS.get_unchecked(-dec_exp) };
542559

543560
let integral; // integral part of bin_sig * pow10
544561
let fractional; // fractional part of bin_sig * pow10
@@ -608,8 +625,7 @@ where
608625

609626
dec_exp = compute_dec_exp(bin_exp, regular);
610627
let exp_shift = compute_exp_shift(bin_exp, dec_exp);
611-
let (mut pow10_hi, mut pow10_lo) =
612-
*unsafe { POW10_SIGNIFICANDS.get_unchecked((-dec_exp - DEC_EXP_MIN) as usize) };
628+
let (mut pow10_hi, mut pow10_lo) = *unsafe { POW10_SIGNIFICANDS.get_unchecked(-dec_exp) };
613629

614630
// Fallback to Schubfach to guarantee correctness in boundary cases. This
615631
// requires switching to strict overestimates of powers of 10.

src/tests.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn utilities() {
2525

2626
#[test]
2727
fn umul_upper_inexact_to_odd() {
28-
let (hi, lo) = crate::POW10_SIGNIFICANDS[0];
28+
let (hi, lo) = crate::POW10_SIGNIFICANDS[-292];
2929
assert_eq!(
3030
crate::umul_upper_inexact_to_odd(hi, lo, 0x1234567890abcdefu64 << 1),
3131
0x24554a3ce60a45f5,
@@ -38,6 +38,8 @@ fn umul_upper_inexact_to_odd() {
3838

3939
#[test]
4040
fn pow10() {
41+
const DEC_EXP_MIN: i32 = -292;
42+
4143
// Range of decimal exponents [K_min, K_max] from the paper.
4244
let dec_exp_min = -324_i32;
4345
let dec_exp_max = 292_i32;
@@ -59,6 +61,6 @@ fn pow10() {
5961
};
6062
let hi = u64::try_from(&result >> 64).unwrap();
6163
let lo = u64::try_from(result & (Uint::from(2_u8).pow(64) - Uint::from(1_u8))).unwrap();
62-
assert_eq!((hi, lo), crate::POW10_SIGNIFICANDS[i]);
64+
assert_eq!(crate::POW10_SIGNIFICANDS[DEC_EXP_MIN + i as i32], (hi, lo));
6365
}
6466
}

0 commit comments

Comments
 (0)