0

I am trying to write a program to find the nth prime. To do this I use the limit given by the prime number theorem:

p(n) < n(ln(n) + ln(ln(n))

to calculate an upper bound for the nth prime number, use constant generics to create an array of that length and then perform a sieve of Eratosthenes to find all primes in that array. However, I have run into the issue that my current code will not compile due to the line:

const N_PRIME: i32 = 10_001;
// ceil use instead of floor to remove possibility of floating point error causing issue with bound
// 1 added to account for array indices starting from 0
const UP_TO: i32 = {let np = N_PRIME as f64; (np * (np.ln() + np.ln().ln())).ceil() as i32 + 1};

with the error message

 const UP_TO: i32 = {let np = N_PRIME as f64; (np * (np.ln() + np.ln().ln())).ceil() as i32 + 1};
  |                                                        ^^^^
  |
  = note: calls in constants are limited to constant functions, tuple structs and tuple variants

naturally I could simply calculate UP_TO and hardcode it, or I could rewrite the code to use vectors. However, the former approach is more clunky and the latter would be slightly slower so a workaround would be preferable. Can anyone think of a way to get the needed value into the UP_TO constant?

Thanks

Edit: Code suggested by pigionhands (as I understand it), this code results in the same error:

const N_PRIME: i32 = 10_001;

fn up_to<const N_PRIME: i32>() -> usize {
    let np = N_PRIME as f64;
    (np * (np.ln() + np.ln().ln())).ceil() as usize + 1
} 

fn main() {
    println!("{}", UP_TO);
    let test_arr = [0; up_to::<N_PRIME>()];
}
Pioneer_11
  • 670
  • 4
  • 19
  • 1
    You can just put it in a normal function. With optimization enabled, it will be resolved at compile time. https://godbolt.org/z/84h6YdqMY – pigeonhands Jan 10 '23 at 02:13
  • @pigeonhands I tried the approach you suggest but it just runs into exactly the same issue. – Pioneer_11 Jan 10 '23 at 02:28
  • Its not going to work for assigning it as `const`, but its as-good-as. The function will be resolved to a const value at compile time and inlined. – pigeonhands Jan 10 '23 at 02:38
  • @pigeonhands as mentioned I need it to be in the form of a const because it the program needs that value to determine the size of an array. – Pioneer_11 Jan 10 '23 at 02:50
  • 1
    Somewhat related is [const_fn_floating_point_arithmetic](https://github.com/rust-lang/rust/issues/57241) I fear until that is resolved and `ln` is marked `const` the only solution is to calculate `UP_TO` by hand and hardcode it. You could use `[debug_]assert_eq!()` to assure both values are in sync. – cafce25 Jan 10 '23 at 03:42
  • Why use an array rather than a `Vec` or boxed slice? Is the heap allocation really that costly? Indeed, if the array is large it could overflow the stack anyway. – eggyal Jan 10 '23 at 05:52
  • @eggyal the speed difference isn't massive but it is there and it seemed like something there should be a solution for. I'm not massively knowledgeable on stack size limits as I'm relatively new to rust having come from python. However, as this is for a sieve of Eratosthenes I only need a boolean value for each index meaning I only need 8 bits per number if using rust's base booleans or one if using bitwise alternatives. As there doesn't seem to be a workaround I'll use vecs instead but this looked like something which should be possible and I like to write fast code whenever I can. – Pioneer_11 Jan 10 '23 at 06:17

0 Answers0