Rastgele büyük primerleri desteklemek için BigUint
'u kullanarak Rust'ta Miller-Rabin Strong Pseudoprime Testini uyguladık. 5 ile 10^6 arasındaki sayılardan geçmek için, cargo run --release
ile yaklaşık 40 saniye sürdü.Sayısal değerdeki büyük tam sayı uygulaması yavaş mı?
Aynı algoritmayı Java'nın BigInteger
ile uygularım ve aynı testin tamamlanması 10 saniye sürdü. Pas 4 kat daha yavaş görünür. Bunun num::bigint
'un uygulanmasından kaynaklandığını farz ediyorum.
Bu yalnızca num::bigint
şu anki durumu mu, yoksa kodumda herhangi bir belirgin iyileşme olan var mı? (Esas olarak dili nasıl kullandım. Algoritma uygulamamın iyi ya da kötü olmasına bakılmaksızın, neredeyse her iki dilde de aynı şekilde uygulanıyor - bu yüzden performanstaki farklılığa neden olmaz.)
Orada fark ettim Rust'un sahip olduğu modele bağlı olarak, clone()
bir çok gereklidir, bu da hızı bir seviyeye kadar etkileyebilir. Ama sanırım bunun bir yolu yok, ben haklı mıyım? Oldukça kolay klon en kaldırabilir
extern crate rand;
extern crate num;
extern crate core;
extern crate time;
use std::time::{Duration};
use time::{now, Tm};
use rand::Rng;
use num::{Zero, One};
use num::bigint::{RandBigInt, BigUint, ToBigUint};
use num::traits::{ToPrimitive};
use num::integer::Integer;
use core::ops::{Add, Sub, Mul, Div, Rem, Shr};
fn find_r_and_d(i: BigUint) -> (u64, BigUint) {
let mut d = i;
let mut r = 0;
loop {
if d.clone().rem(&2u64.to_biguint().unwrap()) == Zero::zero() {
d = d.shr(1usize);
r = r + 1;
} else {
break;
}
}
return (r, d);
}
fn might_be_prime(n: &BigUint) -> bool {
let nsub1 = n.sub(1u64.to_biguint().unwrap());
let two = 2u64.to_biguint().unwrap();
let (r, d) = find_r_and_d(nsub1.clone());
'WitnessLoop: for kk in 0..6u64 {
let a = rand::thread_rng().gen_biguint_range(&two, &nsub1);
let mut x = mod_exp(&a, &d, &n);
if x == 1u64.to_biguint().unwrap() || x == nsub1 {
continue;
}
for rr in 1..r {
x = x.clone().mul(x.clone()).rem(n);
if x == 1u64.to_biguint().unwrap() {
return false;
} else if x == nsub1 {
continue 'WitnessLoop;
}
}
return false;
}
return true;
}
fn mod_exp(base: &BigUint, exponent: &BigUint, modulus: &BigUint) -> BigUint {
let one = 1u64.to_biguint().unwrap();
let mut result = one.clone();
let mut base_clone = base.clone();
let mut exponent_clone = exponent.clone();
while exponent_clone > 0u64.to_biguint().unwrap() {
if exponent_clone.clone() & one.clone() == one {
result = result.mul(&base_clone).rem(modulus);
}
base_clone = base_clone.clone().mul(base_clone).rem(modulus);
exponent_clone = exponent_clone.shr(1usize);
}
return result;
}
fn main() {
let now1 = now();
for n in 5u64..1_000_000u64 {
let b = n.to_biguint().unwrap();
if might_be_prime(&b) {
println!("{}", n);
}
}
let now2 = now();
println!("{}", now2.to_timespec().sec - now1.to_timespec().sec);
}
Not: 'core :: ops',' std :: ops' olarak yeniden dışa aktarılır, dolayısıyla içe aktarmanız gerekmez. –