-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
powi: Different rounding behaviour between debug and release mode, and across platforms #71355
Comments
Cc @hanna-kruppe @joshtriplett This is surprising to me. Does IEEE not specify Thanks for bringing this up, at the least this needs to be documented better in the reference (like other floating point subtleties, e.g. #55131). |
FWIW, Miri prints
As expected, it matches the debug behavior. However, Miri implements |
LLVM performs constant folding of this intrinsic using the host libm, but perhaps it performs a different computations? If I'm reading cppreference right, since C++11 This might just be an LLVM bug accidentally introduced in the move to C++11. |
Oh, so LLVM should not use |
I assume that was the intent of the particular casts it already uses, but I don't know if "some form of |
In {GCC,Clang} {C,C++} you could also write |
Though at least in GCC, the documentation says that |
Maybe a comment could be added in the documentation of “Using this function is generally faster than using to “Using this function is generally faster than using |
This looks like an LLVM bug, I don't think we should adjust our docs/spec to that. |
I've just wasted a few hours, because I followed the documentation and changed a I would probably move further and make |
This issue seems concerning to me, and it's existed for a while. In my opinion, unless there exists an LLVM issue for this with any chance of getting fixed in a timely manner, we should either clearly document this problem, or perhaps even implement |
Has anyone tried bringing this up with the LLVM folks? OTOH their docs for
For
So possibly this isn't an LLVM bug after all. I am not sure what would be gained by changing the implementation, but I now agree that documenting that powi and powf could have different rounding behavior makes sense. |
#73920 has some more examples of powi differences between platforms and build configurations -- not just for subnormals. I think this is similar to how e.g. IOW, I don't think there is a bug here. Maybe we should explicitly document which functions give precise results and which functions give approximations -- and that the quality of the approximation may differ between platforms and build configurations. |
The IEEE 754 standard does have a "float to integer power" ( let p = 1 << 18;
let x = std::hint::black_box(1.0002812_f32);
let mut x32 = x;
let mut x64 = x as f64;
// compute x.powi(p) with repeated squaring using both f32 and f64
for _ in 0..18 {
x32 *= x32;
x64 *= x64;
}
// results are not dependent on platform or optimizations
assert_eq!(x32, 103689867361950008742584042651648.0);
assert_eq!(x64, 102599571306949897080137924476928.0);
assert_eq!(x32 / x64 as f32, 1.0106267);
// that is what powi currently does at runtime
assert_eq!(x32, x.powi(p));
assert_eq!(x64, (x as f64).powi(p));
// with constant folding, powi is accurate instead
assert_eq!(x64 as f32, 1.0002812_f32.powi(p)); The result from |
Yeah I think that is the key point here. I'll close this issue then. |
I still find it quite problematic, what does
fn main() {
let p = 1 << 18;
let x = 1.0002812_f32;
let xp = x.powi(p);
for dp in -40..40 {
println!("x^(p{dp:+}) < x^p == {}", x.powi(p+dp) < xp);
}
} That program can print:
Sure, the documentation says that This is not the same as e.g. |
🤷 We can reopen this as a docs issue if you prefer. It would be great if you could submit a PR since you seem to have the required domain knowledge. :) |
Found the corresponding llvm-issue: llvm/llvm-project#65088 |
variable-precision float operations can differ depending on optimization levels Follow-up to rust-lang#121793 and rust-lang#118217 that accounts for optimizations changing the precision of these functions. Fixes rust-lang#109118 Fixes rust-lang#71355
variable-precision float operations can differ depending on optimization levels Follow-up to rust-lang#121793 and rust-lang#118217 that accounts for optimizations changing the precision of these functions. Fixes rust-lang#109118 Fixes rust-lang#71355
variable-precision float operations can differ depending on optimization levels Follow-up to rust-lang#121793 and rust-lang#118217 that accounts for optimizations changing the precision of these functions. Fixes rust-lang#109118 Fixes rust-lang#71355
Rollup merge of rust-lang#124609 - RalfJung:float-precision, r=cuviper variable-precision float operations can differ depending on optimization levels Follow-up to rust-lang#121793 and rust-lang#118217 that accounts for optimizations changing the precision of these functions. Fixes rust-lang#109118 Fixes rust-lang#71355
Note: This was deemed a docs issue; see here for more details.
The code below tries to print the minimum positive subnormal number in different ways.
In release mode, this output is given:
In debug mode, this output is given:
That is
2f64.powi(-1074)
gives different results for release and debug mode. The difference seems to come from LLVM's optimizations, as the IR looks like it is usingllvm.powi.f64(2.0, -1074)
.I think this is fine. The difference is only in the subnormal range, and I don't think there are any documented guarantees anywhere that are being broken, but I'm posting this issue to make sure.
(This is on both stable 1.42.0 and on nightly.)
The text was updated successfully, but these errors were encountered: