Why `1f64.sqrt()` is not constant?

I tried to define some constant which could be linked with a sqrt function, and failed with

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
  --> test.rs:17:19
   |
17 | const N_MAX:usize=(((3*M_MAX+1)*M_MAX) as f64).sqrt() as usize;
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

I checked the source of sqrt with f64, found its defination is

    #[must_use = "method returns a new number and does not mutate the original value"]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    pub fn exp(self) -> f64 {
        unsafe { intrinsics::expf64(self) }
    }

which only contains an unsafe block with intrinsics.

But, it is not the reason prevent the function being const, since similar function could be const:

        pub const fn checked_log2(self) -> Option<u32> {
            if self <= 0 {
                None
            } else {
                // SAFETY: We just checked that this number is positive
                let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 };
                Some(log)
            }
        }

Is it a good reason that sqrt could not be const?

The tracking issue for const floating point math is #57241. It looks like some open questions are still unresolved about whether to allow differences to exist in floating point operations depending on whether they are evaluated at compile-time or runtime (since at compile-time it's floating point implemented in software versus in hardware, and hardware varies in implementation).

4 Likes

A similar question: Constant trigonometry - #6 by scottmcm

It's possible that comparatively-well-behaved things like sqrt (smooth, monotonic, one-parameter, etc) could be made const before fundamentally-harder things like sin, though.

EDIT: Actually, the first things that might become const would be the ones that are just basic bit manipulation: abs, copysign, is_sign_negative, etc.

2 Likes

Right now, nothing in floats is stable in const to my knowledge. The intrinsics isn't the issue, as that only requires it be implemented in the compiler (which is the case here). The issue arises when cross-compiling, as different CPUs handle floats in different ways.

It would make sense to do this for IEEE-754 required operations which include square roots, because these operations should already be implemented consistently with perfect rounding.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.