【发布时间】:2019-10-10 22:01:39
【问题描述】:
以 n 作为输入,我试图输出第 n 个素数。 Eratosthenes Sieve 似乎是一个很好的方法,但我对要筛分的数组的大小有疑问。
我使用一个数组,其中每个成员都是 1,并且代表一个数字。如果筛子过滤掉数字,则值变为0,这意味着该数字不是素数。一旦到达值为 1 的第 n 个成员,则返回索引值。
我正在尝试为任何给定的 n 设置一个合理的数组大小。但是我有两个问题。
因为我似乎需要将数组的大小设置为一个常数值,所以我找不到使用 n 的大小来近似所需数组大小的方法。这意味着我总是使用 10e6 大小的数组,即使 n 很小。
这种方法依赖于拥有一个大数组,因为它使用早期值来更改后面的值。这意味着对于 n > 10e7,我的数组会破坏堆栈。有没有办法在不进入堆的情况下解决这个问题?
我尝试使用const 来解决第一个问题,如下所示:
pub fn nth(n: u32) -> u32 {
const ARRAY_SIZE : usize = f(n) // where f(n) is some approximation of required array size
let mut primes: [usize; ARRAY_SIZE] = [1; ARRAY_SIZE];
...
}
但是,它并没有绕过固定数组大小的要求。
有什么建议吗?此外,我对 rust 非常陌生,欢迎提出任何使它更像生锈的建议。
以下是我的尝试,它有一个固定大小的数组,适用于 n
pub fn nth(n: u32) -> u32 {
// Eratosthene's Sieve Algorithm
let mut output: u32 = 0;
let mut primes: [usize; 104_827] = [1; 104_827];
primes[0] = 0;
primes[1] = 0;
let mut prime_count = 0;
for i in 2..(primes.len() as usize) {
if primes[i] == 1 {
if prime_count == n as usize { output = i as u32; }
prime_count += 1;
let mut j: usize = 2;
while i * j <= primes.len() as usize {
primes[i * j] = 0;
j += 1;
}
}
}
output
}
编辑:
感谢您的精彩回答!我已更改函数以使用 (n * (n * n.ln()).ln()) 估计,将 usize 数组替换为布尔向量。遗憾的是,我似乎无法仅在堆栈上使用较低的值,因为当数组大小接近近似值时,基于数组的方法比基于向量的方法更快。
我尝试使用提前返回并省去output,但不知道如何使其工作。我在此编辑的末尾有我的代码,其中注释掉了我试图放置早期返回和unreachable!() 的行,但它总是让我感到恐慌。如果有人能指出我的错误,那就太好了。
我打算按照 NieDzejkob 的建议将最里面的 while 循环更改为 for 循环,但是当我运行 while 与 for 的速度数字时,我发现了 while循环更快。有谁知道为什么会这样?
此外,我在 0-9、11 和 12 质数方面也遇到了一些问题,所以我只是将近似值设置为高于这个范围。
第 100 个素数 while_func = 547, for_func = 547
素数 while_func 152.431µs 与 for_func 216.043µs
第 1000 个素数 while_func = 7927, for_func = 7927
素数 while_func 2.099213ms 与 for_func 3.362854ms
第 10000 个素数 while_func = 104743, for_func = 104743
素数 while_func 28.162967ms 与 for_func 44.967197ms
第 100000 个素数 while_func = 1299721, for_func = 1299721
素数 while_func 339.324756ms 与 for_func 559.755934ms
第 1000000 个素数 while_func = 15485867,for_func = 15485867
素数 while_func 4.151047728s 与 for_func 6.950281943s
pub fn nth(n: u32) -> u32 {
// Eratosthene's Sieve Algorithm
let estimate = estimate_size(n);
let mut primes: Vec<bool> = vec![true; estimate + 1];
primes[0] = false;
primes[1] = false;
let mut output: u32 = 0; // remove if unreachable!() works
let mut prime_count: u32 = 0;
for i in 2..(estimate) {
if primes[i] == true {
if prime_count == n { output = i as u32; }
// if prime_count == n { return i as u32; }
prime_count += 1;
let mut j: usize = 2;
while i * j <= estimate {
primes[i * j] = false;
j += 1;
}
// for j in (2*i ..= estimate).step_by(i) {
// primes[j] = false;
// }
}
}
output
// unreachable!()
}
fn estimate_size(n: u32) -> usize {
if n < 14 {
44 as usize
} else {
let n = n as f64;
(n * (n * n.ln()).ln()).ceil() as usize
}
}
【问题讨论】:
标签: arrays rust sieve-of-eratosthenes