Skip to content

Commit bae1746

Browse files
committed
Copy fast divmod100 from zmij
1 parent 1087e9d commit bae1746

File tree

1 file changed

+42
-26
lines changed

1 file changed

+42
-26
lines changed

src/lib.rs

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ static DECIMAL_PAIRS: DecimalPairs = DecimalPairs(
220220
8081828384858687888990919293949596979899",
221221
);
222222

223+
// Returns {value / 100, value % 100} correct for values of up to 4 digits.
224+
fn divmod100(value: u32) -> (u32, u32) {
225+
debug_assert!(value < 10_000);
226+
const EXP: u32 = 19; // 19 is faster or equal to 12 even for 3 digits.
227+
const SIG: u32 = (1 << EXP) / 100 + 1;
228+
let div = (value * SIG) >> EXP; // value / 100
229+
(div, value - div * 100)
230+
}
231+
223232
/// This function converts a slice of ascii characters into a `&str` starting
224233
/// from `offset`.
225234
///
@@ -266,25 +275,30 @@ macro_rules! impl_Unsigned {
266275
.expect("branch is not hit for types that cannot fit 1E4 (u8)");
267276
let quad = remain % scale;
268277
remain /= scale;
269-
let pair1 = (quad / 100) as usize;
270-
let pair2 = (quad % 100) as usize;
278+
let (pair1, pair2) = divmod100(quad as u32);
271279
unsafe {
272-
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 0));
273-
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 1));
274-
buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 0));
275-
buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 1));
280+
buf[offset + 0]
281+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
282+
buf[offset + 1]
283+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
284+
buf[offset + 2]
285+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
286+
buf[offset + 3]
287+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
276288
}
277289
}
278290

279291
// Format per two digits from the lookup table.
280292
if remain > 9 {
281293
offset -= 2;
282294

283-
let pair = (remain % 100) as usize;
284-
remain /= 100;
295+
let (last, pair) = divmod100(remain as u32);
296+
remain = last as Self;
285297
unsafe {
286-
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair * 2 + 0));
287-
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair * 2 + 1));
298+
buf[offset + 0]
299+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
300+
buf[offset + 1]
301+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
288302
}
289303
}
290304

@@ -349,25 +363,24 @@ impl Unsigned for u128 {
349363
// pull two pairs
350364
let quad = remain % 1_00_00;
351365
remain /= 1_00_00;
352-
let pair1 = (quad / 100) as usize;
353-
let pair2 = (quad % 100) as usize;
366+
let (pair1, pair2) = divmod100(quad as u32);
354367
unsafe {
355-
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 0));
356-
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 1));
357-
buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 0));
358-
buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 1));
368+
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
369+
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
370+
buf[offset + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
371+
buf[offset + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
359372
}
360373
}
361374

362375
// Format per two digits from the lookup table.
363376
if remain > 9 {
364377
offset -= 2;
365378

366-
let pair = (remain % 100) as usize;
367-
remain /= 100;
379+
let (last, pair) = divmod100(remain as u32);
380+
remain = last as u64;
368381
unsafe {
369-
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair * 2 + 0));
370-
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair * 2 + 1));
382+
buf[offset + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 0));
383+
buf[offset + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair as usize * 2 + 1));
371384
}
372385
}
373386

@@ -398,13 +411,16 @@ fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>], n: u64) {
398411
// pull two pairs
399412
let quad = remain % 1_00_00;
400413
remain /= 1_00_00;
401-
let pair1 = (quad / 100) as usize;
402-
let pair2 = (quad % 100) as usize;
414+
let (pair1, pair2) = divmod100(quad as u32);
403415
unsafe {
404-
buf[quad_index * 4 + OFFSET + 0].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 0));
405-
buf[quad_index * 4 + OFFSET + 1].write(*DECIMAL_PAIRS.0.get_unchecked(pair1 * 2 + 1));
406-
buf[quad_index * 4 + OFFSET + 2].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 0));
407-
buf[quad_index * 4 + OFFSET + 3].write(*DECIMAL_PAIRS.0.get_unchecked(pair2 * 2 + 1));
416+
buf[quad_index * 4 + OFFSET + 0]
417+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 0));
418+
buf[quad_index * 4 + OFFSET + 1]
419+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair1 as usize * 2 + 1));
420+
buf[quad_index * 4 + OFFSET + 2]
421+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 0));
422+
buf[quad_index * 4 + OFFSET + 3]
423+
.write(*DECIMAL_PAIRS.0.get_unchecked(pair2 as usize * 2 + 1));
408424
}
409425
}
410426
}

0 commit comments

Comments
 (0)