mirror of
https://github.com/uutils/coreutils
synced 2024-07-21 18:04:45 +00:00
refactor/factor ~ polish spelling (comments, names, and exceptions)
This commit is contained in:
parent
ba7939e142
commit
1a37d502d1
|
@ -1,5 +1,7 @@
|
|||
# Benchmarking `factor`
|
||||
|
||||
<!-- spell-checker:ignore (names) Daniel Lemire * Lemire's ; (misc) nohz -->
|
||||
|
||||
The benchmarks for `factor` are located under `tests/benches/factor`
|
||||
and can be invoked with `cargo bench` in that directory.
|
||||
|
||||
|
@ -13,7 +15,7 @@ a newer version of `rustc`.
|
|||
We currently use [`criterion`] to benchmark deterministic functions,
|
||||
such as `gcd` and `table::factor`.
|
||||
|
||||
However, µbenchmarks are by nature unstable: not only are they specific to
|
||||
However, microbenchmarks are by nature unstable: not only are they specific to
|
||||
the hardware, operating system version, etc., but they are noisy and affected
|
||||
by other tasks on the system (browser, compile jobs, etc.), which can cause
|
||||
`criterion` to report spurious performance improvements and regressions.
|
||||
|
@ -33,13 +35,13 @@ as possible:
|
|||
[`criterion`]: https://bheisler.github.io/criterion.rs/book/index.html
|
||||
[lemire]: https://lemire.me/blog/2018/01/16/microbenchmarking-calls-for-idealized-conditions/
|
||||
[isolate a **physical** core]: https://pyperf.readthedocs.io/en/latest/system.html#isolate-cpus-on-linux
|
||||
[frequency stays constant]: XXXTODO
|
||||
[frequency stays constant]: ... <!-- ToDO -->
|
||||
|
||||
|
||||
### Guidance for designing µbenchmarks
|
||||
### Guidance for designing microbenchmarks
|
||||
|
||||
*Note:* this guidance is specific to `factor` and takes its application domain
|
||||
into account; do not expect it to generalise to other projects. It is based
|
||||
into account; do not expect it to generalize to other projects. It is based
|
||||
on Daniel Lemire's [*Microbenchmarking calls for idealized conditions*][lemire],
|
||||
which I recommend reading if you want to add benchmarks to `factor`.
|
||||
|
||||
|
@ -71,7 +73,7 @@ which I recommend reading if you want to add benchmarks to `factor`.
|
|||
|
||||
### Configurable statistical estimators
|
||||
|
||||
`criterion` always uses the arithmetic average as estimator; in µbenchmarks,
|
||||
`criterion` always uses the arithmetic average as estimator; in microbenchmarks,
|
||||
where the code under test is fully deterministic and the measurements are
|
||||
subject to additive, positive noise, [the minimum is more appropriate][lemire].
|
||||
|
||||
|
@ -81,10 +83,10 @@ subject to additive, positive noise, [the minimum is more appropriate][lemire].
|
|||
Measuring performance on real hardware is important, as it relates directly
|
||||
to what users of `factor` experience; however, such measurements are subject
|
||||
to the constraints of the real-world, and aren't perfectly reproducible.
|
||||
Moreover, the mitigations for it (described above) aren't achievable in
|
||||
Moreover, the mitigation for it (described above) isn't achievable in
|
||||
virtualized, multi-tenant environments such as CI.
|
||||
|
||||
Instead, we could run the µbenchmarks in a simulated CPU with [`cachegrind`],
|
||||
Instead, we could run the microbenchmarks in a simulated CPU with [`cachegrind`],
|
||||
measure execution “time” in that model (in CI), and use it to detect and report
|
||||
performance improvements and regressions.
|
||||
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
//! 2 has no multiplicative inverse mode 2^64 because 2 | 2^64,
|
||||
//! and in any case divisibility by two is trivial by checking the LSB.
|
||||
|
||||
// spell-checker:ignore (ToDO) invs newr newrp newtp outstr
|
||||
|
||||
#![cfg_attr(test, allow(dead_code))]
|
||||
|
||||
use std::env::{self, args};
|
||||
|
@ -60,13 +58,13 @@ fn main() {
|
|||
let mut x = primes.next().unwrap();
|
||||
for next in primes {
|
||||
// format the table
|
||||
let outstr = format!("({}, {}, {}),", x, modular_inverse(x), std::u64::MAX / x);
|
||||
if cols + outstr.len() > MAX_WIDTH {
|
||||
write!(file, "\n {}", outstr).unwrap();
|
||||
cols = 4 + outstr.len();
|
||||
let output = format!("({}, {}, {}),", x, modular_inverse(x), std::u64::MAX / x);
|
||||
if cols + output.len() > MAX_WIDTH {
|
||||
write!(file, "\n {}", output).unwrap();
|
||||
cols = 4 + output.len();
|
||||
} else {
|
||||
write!(file, " {}", outstr).unwrap();
|
||||
cols += 1 + outstr.len();
|
||||
write!(file, " {}", output).unwrap();
|
||||
cols += 1 + output.len();
|
||||
}
|
||||
|
||||
x = next;
|
||||
|
@ -81,7 +79,7 @@ fn main() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_generator_isprime() {
|
||||
fn test_generator_is_prime() {
|
||||
assert_eq!(Sieve::odd_primes.take(10_000).all(is_prime));
|
||||
}
|
||||
|
||||
|
@ -106,5 +104,5 @@ const PREAMBLE: &str = r##"/*
|
|||
// re-run src/factor/gen_tables.rs.
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
pub const P_INVS_U64: &[(u64, u64, u64)] = &[
|
||||
pub const PRIME_INVERSIONS_U64: &[(u64, u64, u64)] = &[
|
||||
"##;
|
||||
|
|
|
@ -17,6 +17,7 @@ type Exponent = u8;
|
|||
#[derive(Clone, Debug)]
|
||||
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);
|
||||
|
||||
// spell-checker:ignore (names) Erdős–Kac * Erdős Kac
|
||||
// The number of factors to inline directly into a `Decomposition` object.
|
||||
// As a consequence of the Erdős–Kac theorem, the average number of prime factors
|
||||
// of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use a slightly higher value.
|
||||
|
@ -250,6 +251,7 @@ impl Distribution<Factors> for Standard {
|
|||
let mut g = 1u64;
|
||||
let mut n = u64::MAX;
|
||||
|
||||
// spell-checker:ignore (names) Adam Kalai * Kalai's
|
||||
// Adam Kalai's algorithm for generating uniformly-distributed
|
||||
// integers and their factorization.
|
||||
//
|
||||
|
|
|
@ -21,6 +21,7 @@ impl Basis for Montgomery<u64> {
|
|||
}
|
||||
|
||||
impl Basis for Montgomery<u32> {
|
||||
// spell-checker:ignore (names) Steve Worley
|
||||
// Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
|
||||
// discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
|
@ -121,8 +122,8 @@ mod tests {
|
|||
}
|
||||
|
||||
fn odd_primes() -> impl Iterator<Item = u64> {
|
||||
use crate::table::{NEXT_PRIME, P_INVS_U64};
|
||||
P_INVS_U64
|
||||
use crate::table::{NEXT_PRIME, PRIME_INVERSIONS_U64};
|
||||
PRIME_INVERSIONS_U64
|
||||
.iter()
|
||||
.map(|(p, _, _)| *p)
|
||||
.chain(iter::once(NEXT_PRIME))
|
||||
|
|
|
@ -93,7 +93,7 @@ mod tests {
|
|||
gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
|
||||
}
|
||||
|
||||
fn scalar_mult(a: u64, b: u64, k: u64) -> bool {
|
||||
fn scalar_multiplication(a: u64, b: u64, k: u64) -> bool {
|
||||
gcd(k * a, k * b) == k * gcd(a, b)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
|
|||
debug_assert!(a % (one + one) == one, "{:?} is not odd", a);
|
||||
|
||||
let mut t = zero;
|
||||
let mut newt = one;
|
||||
let mut new_t = one;
|
||||
let mut r = zero;
|
||||
let mut newr = a;
|
||||
let mut new_r = a;
|
||||
|
||||
while newr != zero {
|
||||
while new_r != zero {
|
||||
let quot = if r == zero {
|
||||
// special case when we're just starting out
|
||||
// This works because we know that
|
||||
|
@ -28,15 +28,15 @@ pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
|
|||
T::max_value()
|
||||
} else {
|
||||
r
|
||||
} / newr;
|
||||
} / new_r;
|
||||
|
||||
let newtp = t.wrapping_sub(".wrapping_mul(&newt));
|
||||
t = newt;
|
||||
newt = newtp;
|
||||
let new_tp = t.wrapping_sub(".wrapping_mul(&new_t));
|
||||
t = new_t;
|
||||
new_t = new_tp;
|
||||
|
||||
let newrp = r.wrapping_sub(".wrapping_mul(&newr));
|
||||
r = newr;
|
||||
newr = newrp;
|
||||
let new_rp = r.wrapping_sub(".wrapping_mul(&new_r));
|
||||
r = new_r;
|
||||
new_r = new_rp;
|
||||
}
|
||||
|
||||
debug_assert_eq!(r, one);
|
||||
|
|
|
@ -69,7 +69,7 @@ impl<T: DoubleInt> Montgomery<T> {
|
|||
let t_bits = T::zero().count_zeros() as usize;
|
||||
|
||||
debug_assert!(x < (self.n.as_double_width()) << t_bits);
|
||||
// TODO: optimiiiiiiise
|
||||
// TODO: optimize
|
||||
let Montgomery { a, n } = self;
|
||||
let m = T::from_double_width(x).wrapping_mul(a);
|
||||
let nm = (n.as_double_width()) * (m.as_double_width());
|
||||
|
@ -138,7 +138,7 @@ impl<T: DoubleInt> Arithmetic for Montgomery<T> {
|
|||
r + self.n.wrapping_neg()
|
||||
};
|
||||
|
||||
// Normalise to [0; n[
|
||||
// Normalize to [0; n[
|
||||
let r = if r < self.n { r } else { r - self.n };
|
||||
|
||||
// Check that r (reduced back to the usual representation) equals
|
||||
|
@ -200,7 +200,7 @@ mod tests {
|
|||
}
|
||||
parametrized_check!(test_add);
|
||||
|
||||
fn test_mult<A: DoubleInt>() {
|
||||
fn test_multiplication<A: DoubleInt>() {
|
||||
for n in 0..100 {
|
||||
let n = 2 * n + 1;
|
||||
let m = Montgomery::<A>::new(n);
|
||||
|
@ -213,7 +213,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
parametrized_check!(test_mult);
|
||||
parametrized_check!(test_multiplication);
|
||||
|
||||
fn test_roundtrip<A: DoubleInt>() {
|
||||
for n in 0..100 {
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::Factors;
|
|||
include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));
|
||||
|
||||
pub fn factor(num: &mut u64, factors: &mut Factors) {
|
||||
for &(prime, inv, ceil) in P_INVS_U64 {
|
||||
for &(prime, inv, ceil) in PRIME_INVERSIONS_U64 {
|
||||
if *num == 1 {
|
||||
break;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ pub fn factor(num: &mut u64, factors: &mut Factors) {
|
|||
|
||||
pub const CHUNK_SIZE: usize = 8;
|
||||
pub fn factor_chunk(n_s: &mut [u64; CHUNK_SIZE], f_s: &mut [Factors; CHUNK_SIZE]) {
|
||||
for &(prime, inv, ceil) in P_INVS_U64 {
|
||||
for &(prime, inv, ceil) in PRIME_INVERSIONS_U64 {
|
||||
if n_s[0] == 1 && n_s[1] == 1 && n_s[2] == 1 && n_s[3] == 1 {
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue