Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking issue for #![feature(const_fn_floating_point_arithmetic)] #57241

Closed
Centril opened this issue Dec 31, 2018 · 53 comments · Fixed by #128596
Closed

Tracking issue for #![feature(const_fn_floating_point_arithmetic)] #57241

Centril opened this issue Dec 31, 2018 · 53 comments · Fixed by #128596
Labels
A-const-eval Area: constant evaluation (mir interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. S-tracking-design-concerns Status: There are blocking ❌ design concerns. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Centril
Copy link
Contributor

Centril commented Dec 31, 2018

Sub-tracking issue for rust-lang/rfcs#911.

This tracks arithmetic for floating point types in const fn. These operations are already stable in const/static, and are also being promoted on stable (&(1.2*2.1) has lifetime 'static). However, in all of these situations, the code is definitely executed at compile-time -- only const fn code could be executed both at compile-time and run-time, making possible differences in FP behavior observable. Also see #77745.

Open Questions

@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. A-const-eval Area: constant evaluation (mir interpretation) labels Dec 31, 2018
@Centril Centril added the needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. label Jan 13, 2019
@burrbull
Copy link
Contributor

burrbull commented Feb 9, 2019

Can from_bits / to_bits be made const fn in respect that #53535 ?

@RalfJung
Copy link
Member

One problem with stabilizing floats in consts is that their run-time semantics are broken, and likely unsound: #55131, #73288.

@RalfJung RalfJung changed the title Tracking issue for floating point arithmetic in const fn Tracking issue for floating point arithmetic in const fn (part of const_fn feature gate) Aug 7, 2020
@ecstatic-morse ecstatic-morse changed the title Tracking issue for floating point arithmetic in const fn (part of const_fn feature gate) Tracking issue for floating point arithmetic in const fn (const_fn_floating_point_arithmetic) Sep 26, 2020
@ecstatic-morse ecstatic-morse changed the title Tracking issue for floating point arithmetic in const fn (const_fn_floating_point_arithmetic) Tracking issue for #![feature(const_fn_floating_point_arithmetic)] Sep 26, 2020
@mqudsi
Copy link
Contributor

mqudsi commented Feb 18, 2021

While one concern with const evaluation of floating point math is that the results may differ from the hardware (I think we are still using the host fpu for a lot of f32/f64 stuff in miri) there is a huge benefit to adding const evaluation of floating point arithmetic for no_std environments where runtime (soft or hard) fp math may be unavailable altogether.

In this context, constant evaluation can be a huge boon to embedded developers and significantly raise both ergonomics and code quality by allowing for compile-time substitution of static expressions involving floating point math based off of literal constant parameters without requiring opaque f32/f64 values followed by an outdated comment saying “this is the result of the computation of ....” and without requiring lookup tables that will take up room in the ROM without ever being accessed because the ultimate results are computed dynamically and plugged in at compile-time.

This isn’t even arch-specific, eg currently there’s no way to use f64::powf64 without std except via the intrinsic, but that’s not marked const and shouldn’t be anywhere near the current version of core... except it’s actually perfectly fine to use in core/no_std if evaluated at compile-time (and only at compile-time). Would enabling something like that at compile time require an alternative implementation of the intrinsic or a full restructuring of the std/no_std primitives altogether?

@RalfJung
Copy link
Member

RalfJung commented Feb 18, 2021

(I think we are still using the host fpu for a lot of f32/f64 stuff in miri)

CTFE never uses the host FPU. (Miri-the-tool sometimes does but that is not relevant here.) Floats during CTFE are implemented entirely via "softfloats", i.e., a software-only implementation of IEEE floating point semantics. This means the result is the same no matter the host you use to compile. However, the result might still be different from what would happen on the target since the IEEE float spec doesn't always uniquely determine what happens (in particular around NaNs), and since some targets are not IEEE-compliant.

f64::powf64

pow is not available during CTFE even unstably, since our softlofat library does not support pow (or at least I couldn't find any support for this operation). So to get pow in const even just on nightly (disregarding all the issues that currently block stabilization), someone would have to first implement pow in softfloats.

@RalfJung
Copy link
Member

All the issues around floating-point semantics aside, we do allow floating-point operations in const outside const fn. We also promote floating-point operations, so e.g. &(1.0*2.0) will be evaluated at compile time. So we basically already have to live with whatever our CTFE floating-point semantics are, and we have to be careful with changing it. I don't immediately see how allowing the same operations in const fn would make things any worse... @oli-obk was disallowing this in const fn just done out of abundance of caution, or was there some other concern?

@oli-obk
Copy link
Contributor

oli-obk commented Feb 18, 2021

Entirely done out of an abundance of caution. We just didn't want to have any discussion at min_const_fn stabilization time, so we avoided it. The only argument against stabilization is that running the same const fn at runtime and at compile time can yield different results, so technically optimizing away a const fn call by evaluating it at optimization time could change program behaviour. There are much worse things (like missing heap allocations) so I think we can safely ignore this argument and just assume that no one can make optimizations that solely depend on the constness of a function.

@RalfJung
Copy link
Member

RalfJung commented Feb 18, 2021

Doesn't ConstProp already use CTFE floats to optimize runtime code?

Also, if this is considered "changing program behavior", that would mean Rust floats would not be specified as "IEEE floats" but as "whatever-the-target-does floats". I don't think that decision was ever made, was it? It would arguably mean that Miri and CTFE are buggy if they diverge from the target behavior.

If Rust is specified as using IEEE floats, then the NaN bits are not specified, and it's okay for them to come out either way. With this view, there is no change in program behavior, just a different non-deterministic choice being made.

@oli-obk
Copy link
Contributor

oli-obk commented Feb 18, 2021

Doesn't ConstProp already use CTFE floats to optimize runtime code?

no, we explicitly opt out of floats.

. I don't think that decision was ever made, was it?

It was not, I was just reiterating the argument that was made here. I don't remember who made the argument or whether they thought it an important argument, I just remember that it was easier to punt the decision into the future. I personally think we should just stabilize floats in const fn

@RalfJung
Copy link
Member

no, we explicitly opt out of floats.

Oh, interesting.
We do promote floating-point-ops though which is not too different from an optimization. (And I recently tried to disable that and found too many uses. Maybe we could disable it in fn/const fn only but still promote in static/const; not sure if that's worth it.)

@workingjubilee
Copy link
Member

@oli-obk

There are much worse things (like missing heap allocations) just assume that no one can make optimizations that solely depend on the constness of a function.

I am not sure I understand the first half of this sentence. What do you mean by missing heap allocations? And are there actually any such optimizations?

@RalfJung

since the IEEE float spec doesn't always uniquely determine what happens (in particular around NaNs),

Which are you thinking of in particular? IEEE754-2008 adds clauses that define a few NaN-related behaviors for floating point.

re: the overall subject, I think it is possible to make Rust floats have a reasonably Rust-defined behavior so I do not think we should blink here, at least not just yet.

@Rudxain
Copy link
Contributor

Rudxain commented Feb 11, 2023

FiniteFxx could then have const arithmetic where NaN would be represented by None. fxx const arithmetic can then be implemented as unwrapping the result of FiniteFxx arithmetic.

This is genius! This also improves the type safety of the language, as NaN is similar to null (in other langs), in the sense that it's a placeholder for any invalid or non-existent value. NaN could also be the result of an operation that returns a valid number in a non-Real set (like Complex numbers), so it makes sense that NaN should be represented as its own value, outside of the set of floats (because it shouldn't be a valid float)

@programmerjake
Copy link
Member

FiniteFxx could then have const arithmetic where NaN would be represented by None. fxx const arithmetic can then be implemented as unwrapping the result of FiniteFxx arithmetic.

imho having FiniteFxx is fine (though I would keep both +0.0 and -0.0 to match IEEE 754's definition of finite).

imho using FiniteFxx to implement const fxx arithmetic is probably terrible, floats have infinities for a good reason, and conflating them with NaNs is not helpful.

if I were to design const floats for Rust and get consistent cross-architecture results and weren't trying to match any particular architecture, I'd follow more or less what RISC-V, JavaScript, and Java do, and keep all results identical to what IEEE 754 specifies except for NaNs. I'd always have non-pure-bitwise fp ops (so everything but neg, copysign, abs, and friends) produce a known canonical NaN value (e.g. iirc RISC-V picked 0x7FC00000 for f32) everytime they output any NaN.

@scottmcm
Copy link
Member

+1 to keeping the infinities -- they're useful, don't have the ambiguity problems of NANs, and don't keep the type from being Ord.

@p-avital
Copy link

My reason for trimming all these values was to make certain that not ambiguity ever exists, but I'm also fine with keeping -0.0 and infinities if the people with more knowledge of floats confirm that there aren't any operations that may pick arbitrarily between them.

They couldn't be called finite anymore though: OrdFxx? Any suggestions?

@programmerjake
Copy link
Member

They couldn't be called finite anymore though: OrdFxx? Any suggestions?

I've seen them referred to as NonNanF32 (with casing TBD), similar to NonZeroU32

@RalfJung
Copy link
Member

RalfJung commented Feb 12, 2023

Note that we already do allow floating point operations in const/static initializers. It's only const fn where they are currently forbidden.

So something like only allowing NonNanF32 in const would either be a massive breaking change, or we'd still have the strange situation of having different rules in const vs const fn.

@programmerjake
Copy link
Member

I'm all for f32/f64 support in const fn, once we figure out the exact semantics, which imho should either match LLVM (which is currently being discussed), or be specified kinda like RISC-V, Java, and JavaScript, as I explained in more detail above in #57241 (comment)

NonNanF32 is just a nice addition that can be pursued independently.

@str4d
Copy link
Contributor

str4d commented Feb 16, 2023

Would it be reasonable, as a stepping stone, to stabilise subsets of what is currently covered by #![feature(const_fn_floating_point_arithmetic)] that can be defined unambiguously (if such subsets exist)? For example, I'd be interested in knowing if impl PartialEq for {f32, f64} could be stabilised independently of the rest of the arithmetic.

My particular motivation is that I have a C FFI that takes a C struct containing an f32, which for lifetime reasons needs to be defined as &'static. I want to provide a nice wrapper type that users can define as constants, and I want to enforce range constraints (namely assert!(value >= 0.0 && value <= 1.0) because this particular value represents a percentage).

@workingjubilee
Copy link
Member

My current goal regarding solving this issue is to make progress on allowing to_bits and from_bits in const fn, without addressing any of the other issues involved, and without entailing e.g. resolving const-time NaN semantics or anything like that. This will allow people to build what solutions they may on top of that.

@clarfonthey
Copy link
Contributor

+1 to allowing from_bits and to_bits; for a ratio library I've been working on I craft an f64 by hand since I don't trust hardware to round correctly and having to transmute the result is the only unsafe code in the whole thing.

maxdeviant added a commit to zed-industries/zed that referenced this issue Mar 14, 2024
This PR adds a new `rems_from_px` helper function that can be used to
compute rem values based on a pixel value.

This is something we do fairly commonly, where we want to express a size
that is a given pixel size at the base rem size (e.g., "14px when the
rem size is 16px").

`rems_from_px` helps make the intent more explicit, as well as prevent
the base rem size from being duplicated everywhere.

Note: Ideally we would want `rems_from_px` to be `const`, but that
depends on rust-lang/rust#57241.

Release Notes:

- N/A
@matklad
Copy link
Member

matklad commented Jun 16, 2024

One small stabilizable subset is is_nan function --- regardless of which NaN value a particular implementation uses, they all agree on the set of values considered NaN.

In my use-case (implementing something like NonNanF64), is_nan is the only const fn I need.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jun 17, 2024 via email

@oli-obk
Copy link
Contributor

oli-obk commented Jun 18, 2024

I would prefer to just go all in and land rust-lang/rfcs#3514

Adding exceptions for individual functions requires extra logic and will just cause us to spend a lot of time on discussing individual items

edit: I "made progress" on that RFC by pinging all the T-lang members that have unchecked boxes 😆

@RalfJung
Copy link
Member

RalfJung commented Aug 3, 2024

We're finally moving ahead with stabilization here. :)
#128596

@jhpratt jhpratt changed the title Tracking issue for #![feature(const_fn_floating_point_arithmetic)] low quality Aug 3, 2024
@jhpratt jhpratt changed the title low quality Tracking issue for #![feature(const_fn_floating_point_arithmetic)] Aug 4, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 24, 2024
…rithmetic, r=nnethercote

stabilize const_fn_floating_point_arithmetic

Part of rust-lang#128288
Fixes rust-lang#57241

The existing test `tests/ui/consts/const_let_eq_float.rs`  ([link](https://github.com/RalfJung/rust/blob/const_fn_floating_point_arithmetic/tests/ui/consts/const_let_eq_float.rs)) covers the basics, and also Miri has extensive tests covering the interpreter's float machinery. Also, that machinery can already be used on stable inside `const`/`static` initializers, just not inside `const fn`.

This was explicitly called out in rust-lang/rfcs#3514 so in a sense t-lang just recently already FCP'd this, but let's hear from them whether they want another FCP for the stabilization here or whether that was covered by the FCP for the RFC.
Cc `@rust-lang/lang`

### Open items

- [x] Update the Reference: rust-lang/reference#1566
@bors bors closed this as completed in 0dfdea1 Aug 25, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Aug 25, 2024
Rollup merge of rust-lang#128596 - RalfJung:const_fn_floating_point_arithmetic, r=nnethercote

stabilize const_fn_floating_point_arithmetic

Part of rust-lang#128288
Fixes rust-lang#57241

The existing test `tests/ui/consts/const_let_eq_float.rs`  ([link](https://github.com/RalfJung/rust/blob/const_fn_floating_point_arithmetic/tests/ui/consts/const_let_eq_float.rs)) covers the basics, and also Miri has extensive tests covering the interpreter's float machinery. Also, that machinery can already be used on stable inside `const`/`static` initializers, just not inside `const fn`.

This was explicitly called out in rust-lang/rfcs#3514 so in a sense t-lang just recently already FCP'd this, but let's hear from them whether they want another FCP for the stabilization here or whether that was covered by the FCP for the RFC.
Cc ``@rust-lang/lang``

### Open items

- [x] Update the Reference: rust-lang/reference#1566
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Aug 26, 2024
…, r=nnethercote

stabilize const_fn_floating_point_arithmetic

Part of rust-lang/rust#128288
Fixes rust-lang/rust#57241

The existing test `tests/ui/consts/const_let_eq_float.rs`  ([link](https://github.com/RalfJung/rust/blob/const_fn_floating_point_arithmetic/tests/ui/consts/const_let_eq_float.rs)) covers the basics, and also Miri has extensive tests covering the interpreter's float machinery. Also, that machinery can already be used on stable inside `const`/`static` initializers, just not inside `const fn`.

This was explicitly called out in rust-lang/rfcs#3514 so in a sense t-lang just recently already FCP'd this, but let's hear from them whether they want another FCP for the stabilization here or whether that was covered by the FCP for the RFC.
Cc ``@rust-lang/lang``

### Open items

- [x] Update the Reference: rust-lang/reference#1566
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: constant evaluation (mir interpretation) A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. S-tracking-design-concerns Status: There are blocking ❌ design concerns. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.