Skip to content

Commit

Permalink
Merge pull request #53 from dtolnay/sync
Browse files Browse the repository at this point in the history
Reimplement pow5_factor using modular inverse
  • Loading branch information
dtolnay committed Dec 9, 2023
2 parents f84f806 + 2e482fc commit 5bfd87c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ C, [https://github.com/ulfjack/ryu][upstream].
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/abf76d252bc97300354857e64e80d4a2bf664291
[upstream]: https://github.com/ulfjack/ryu/tree/77e767f5e056bab96e895072fc21618ecff2f44b

```toml
[dependencies]
Expand Down
10 changes: 5 additions & 5 deletions src/d2s_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ pub fn div100(x: u64) -> u64 {
}

#[cfg_attr(feature = "no-panic", inline)]
fn pow5_factor(mut value: u64) -> u32 {
pub(crate) fn pow5_factor(mut value: u64) -> u32 {
const M_INV_5: u64 = 14757395258967641293; // 5 * m_inv_5 = 1 (mod 2^64)
const N_DIV_5: u64 = 3689348814741910323; // #{ n | n = 0 (mod 2^64) } = 2^64 / 5
let mut count = 0u32;
loop {
debug_assert!(value != 0);
let q = div5(value);
let r = (value as u32).wrapping_sub(5u32.wrapping_mul(q as u32));
if r != 0 {
value = value.wrapping_mul(M_INV_5);
if value > N_DIV_5 {
break;
}
value = q;
count += 1;
}
count
Expand Down
72 changes: 72 additions & 0 deletions tests/d2s_intrinsics_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Translated from C to Rust. The original C code can be found at
// https://github.com/ulfjack/ryu and carries the following license:
//
// Copyright 2018 Ulf Adams
//
// The contents of this file may be used under the terms of the Apache License,
// Version 2.0.
//
// (See accompanying file LICENSE-Apache or copy at
// http://www.apache.org/licenses/LICENSE-2.0)
//
// Alternatively, the contents of this file may be used under the terms of
// the Boost Software License, Version 1.0.
// (See accompanying file LICENSE-Boost or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Unless required by applicable law or agreed to in writing, this software
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.

#![allow(dead_code)]
#![allow(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::unreadable_literal
)]

#[path = "../src/d2s_intrinsics.rs"]
mod d2s_intrinsics;

use d2s_intrinsics::pow5_factor;

#[test]
fn test_pow5_factor() {
assert_eq!(0, pow5_factor(1));
assert_eq!(0, pow5_factor(2));
assert_eq!(0, pow5_factor(3));
assert_eq!(0, pow5_factor(4));
assert_eq!(1, pow5_factor(5));
assert_eq!(0, pow5_factor(6));
assert_eq!(0, pow5_factor(7));
assert_eq!(0, pow5_factor(8));
assert_eq!(0, pow5_factor(9));
assert_eq!(1, pow5_factor(10));

assert_eq!(0, pow5_factor(12));
assert_eq!(0, pow5_factor(14));
assert_eq!(0, pow5_factor(16));
assert_eq!(0, pow5_factor(18));
assert_eq!(1, pow5_factor(20));

assert_eq!(2, pow5_factor(5 * 5));
assert_eq!(3, pow5_factor(5 * 5 * 5));
assert_eq!(4, pow5_factor(5 * 5 * 5 * 5));
assert_eq!(5, pow5_factor(5 * 5 * 5 * 5 * 5));
assert_eq!(6, pow5_factor(5 * 5 * 5 * 5 * 5 * 5));
assert_eq!(7, pow5_factor(5 * 5 * 5 * 5 * 5 * 5 * 5));
assert_eq!(8, pow5_factor(5 * 5 * 5 * 5 * 5 * 5 * 5 * 5));
assert_eq!(9, pow5_factor(5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5));
assert_eq!(10, pow5_factor(5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5));

assert_eq!(0, pow5_factor(42));
assert_eq!(1, pow5_factor(42 * 5));
assert_eq!(2, pow5_factor(42 * 5 * 5));
assert_eq!(3, pow5_factor(42 * 5 * 5 * 5));
assert_eq!(4, pow5_factor(42 * 5 * 5 * 5 * 5));
assert_eq!(5, pow5_factor(42 * 5 * 5 * 5 * 5 * 5));

assert_eq!(27, pow5_factor(7450580596923828125)); // 5^27, largest power of 5 < 2^64.
assert_eq!(1, pow5_factor(18446744073709551615)); // 2^64 - 1, largest multiple of 5 < 2^64.
assert_eq!(0, pow5_factor(18446744073709551614)); // 2^64 - 2, largest non-multiple of 5 < 2^64.
}

0 comments on commit 5bfd87c

Please sign in to comment.