Last active
August 5, 2018 06:33
-
-
Save koba-e964/ebe145d730bcf3e0210212e813cf52eb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rustup run nightly rustc --test -O pollard_rho.rs | |
./pollard_rho --bench |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(test)] | |
extern crate test; | |
mod pollard_rho { | |
use std::collections::HashMap; | |
fn gcd(mut x: i64, mut y: i64) -> i64 { | |
while y != 0 { | |
let r = x % y; x = y; y = r; | |
} | |
x | |
} | |
fn add_mod(x: i64, y: i64, n: i64) -> i64 { | |
let z = x + y; | |
if z >= n { z - n } else { z } | |
} | |
fn mul_mod(x: i64, mut y: i64, n: i64) -> i64 { | |
assert!(x >= 0); | |
assert!(x < n); | |
let mut sum = 0; | |
let mut cur = x; | |
while y > 0 { | |
if y % 2 == 1 { | |
sum = add_mod(sum, cur, n); | |
} | |
cur = add_mod(cur, cur, n); | |
y /= 2; | |
} | |
sum | |
} | |
fn mod_pow(x: i64, mut e: i64, n: i64) -> i64 { | |
let mut prod = if n == 1 { 0 } else { 1 }; | |
let mut cur = x % n; | |
while e > 0 { | |
if e % 2 == 1 { | |
prod = mul_mod(prod, cur, n); | |
} | |
cur = mul_mod(cur, cur, n); | |
e /= 2; | |
} | |
prod | |
} | |
pub fn is_prime(n: i64) -> bool { | |
if n <= 1 { return false; } | |
let small = [2, 3, 5, 7, 11, 13]; | |
if small.iter().any(|&u| u == n) { return true; } | |
if small.iter().any(|&u| n % u == 0) { return false; } | |
let mut d = n - 1; | |
let mut e = 0; | |
while d % 2 == 0 { | |
d /= 2; | |
e += 1; | |
} | |
let a = [2, 325, 9375, 28178, 450775, 9780504, 1795265022]; | |
a.iter().all(|&a| { | |
if a >= n { return true; } | |
let mut x = mod_pow(a, d, n); | |
if x == 1 { return true; } | |
for _ in 0 .. e { | |
if x == n - 1 { | |
return true; | |
} | |
x = mul_mod(x, x, n); | |
if x == 1 { return false; } | |
} | |
x == 1 | |
}) | |
} | |
fn pollard_rho(n: i64, c: &mut i64) -> i64 { | |
if n % 2 == 0 { return 2; } | |
loop { | |
let mut x: i64 = 2; | |
let mut y = 2; | |
let mut d = 1; | |
let cc = *c; | |
let f = |i| (mul_mod(i, i, n) + cc) % n; | |
while d == 1 { | |
x = f(x); | |
y = f(f(y)); | |
d = gcd((x - y).abs(), n); | |
} | |
if d == n { | |
*c += 1; | |
continue; | |
} | |
return d; | |
} | |
} | |
/// Outputs (p, e) in p's ascending order. | |
pub fn factorize(x: i64) -> Vec<(i64, usize)> { | |
if x <= 1 { | |
return Vec::new(); | |
} | |
let mut hm = HashMap::new(); | |
let mut pool = vec![x]; | |
let mut c = 1; | |
while let Some(u) = pool.pop() { | |
if is_prime(u) { | |
*hm.entry(u).or_insert(0) += 1; | |
continue; | |
} | |
let p = pollard_rho(u, &mut c); | |
pool.push(p); | |
pool.push(u / p); | |
} | |
let mut v: Vec<_> = hm.into_iter().collect(); | |
v.sort(); | |
v | |
} | |
} // mod pollard_rho | |
#[cfg(test)] | |
mod tests { | |
use pollard_rho::*; | |
use test::Bencher; | |
use test::*; | |
#[test] | |
fn test1() { | |
assert_eq!(factorize(12), vec![(2, 2), (3, 1)]); | |
} | |
#[test] | |
fn test2() { | |
assert_eq!(factorize(100067993986373873), | |
vec![(16310299, 1), (6135264227, 1)]); | |
} | |
#[bench] | |
fn bench_factorize_around_2_pow_32(b: &mut Bencher) { | |
b.iter(|| { | |
let mut sum = 0; | |
for i in 1 << 32 .. (1 << 32) + 10 { | |
for (p, e) in factorize(i) { | |
sum ^= p; | |
sum ^= e as i64; | |
} | |
} | |
sum | |
}); | |
} | |
#[bench] | |
fn bench_is_prime_around_2_pow_32(b: &mut Bencher) { | |
b.iter(|| { | |
let mut sum = 0; | |
for i in 1 << 32 .. (1 << 32) + 100 { | |
if is_prime(i) { | |
sum ^= i; | |
} | |
} | |
sum | |
}); | |
} | |
#[bench] | |
fn bench_is_prime_2_pow_32_plus_15(b: &mut Bencher) { | |
b.iter(|| { | |
let value = black_box((1 << 32) + 15); | |
is_prime(value) | |
}); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
running 5 tests | |
test tests::test1 ... ignored | |
test tests::test2 ... ignored | |
test tests::bench_factorize_around_2_pow_32 ... bench: 795,275 ns/iter (+/- 1,351,615) | |
test tests::bench_is_prime_2_pow_32_plus_15 ... bench: 61,162 ns/iter (+/- 14,716) | |
test tests::bench_is_prime_around_2_pow_32 ... bench: 537,013 ns/iter (+/- 152,748) | |
test result: ok. 0 passed; 0 failed; 2 ignored; 3 measured; 0 filtered out | |
running 5 tests | |
test tests::test1 ... ignored | |
test tests::test2 ... ignored | |
test tests::bench_factorize_around_2_pow_32 ... bench: 802,402 ns/iter (+/- 351,642) | |
test tests::bench_is_prime_2_pow_32_plus_15 ... bench: 59,492 ns/iter (+/- 20,175) | |
test tests::bench_is_prime_around_2_pow_32 ... bench: 490,505 ns/iter (+/- 306,927) | |
test result: ok. 0 passed; 0 failed; 2 ignored; 3 measured; 0 filtered out | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment