Why is f64::powf not a const fn?

I just ran into a failure:

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
  --> src/system/wca.rs:14:23
   |
14 | const R_CUTOFF: f64 = 2.0_f64.powf(1.0/6.0);
   |

I'm puzzled as to why f64::powf would not be const. Is this something that is going to change?

No floating point function has been const-ified yet. This is likely due to floating point being very hard to acurately model due to platform specific differences, this may take a while.

2 Likes

That's too bad. It'll be really great when I can define my constants using rust code. :frowning:

Some floating point methods are implemented with LLVM intrinsics, like powf as llvm.pow, which may compile to a native instruction or a libm call. Some others are always explicit libm calls.

Miri does have the ability to evaluate these by performing them directly, using host floats, although there's a FIXME on that. So I think that makes it possible for them to be const after all.

I looks like

lazy_static! {
    pub static ref R_CUTOFF: f64 = 2.0_f64.powf(1.0/6.0);
}

works.

Lazy static is always evaluated at runtime, so yes that will work. If you can't stand the macro magic, then you can use once_cell, specifically once_cell::sync::Lazy

Worth noting that powf is not even constexpr in C++, which has had far more work put into constification to date than Rust has. Same with sqrt and all of the transcendental functions.

9 Likes

i think the problem with using host floats for constantification is that the compiled binary will depend on what platform it's compiled on, due to subtle FPU differences, adding a factor of non-determinism
so ideally this would use some kind of softfloat implementation

2 Likes