-
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
Two consecutive std::f32::sin()
invocations on the same value give different results in certain scenarios
#109118
Comments
Looking at the assembly outputs I found out that the value Here is the assembly I got from Compiler Explorer for example::main:
push r15
push r14
push r12
push rbx
sub rsp, 88
mov dword ptr [rsp + 12], 1061273700 ; value of a
mov dword ptr [rsp + 16], 1060095721 ; precalculated value of b
lea rax, [rsp + 16]
mov qword ptr [rsp + 24], rax
mov r12, qword ptr [rip + core::fmt::num::<impl core::fmt::LowerHex for u32>::fmt@GOTPCREL]
mov qword ptr [rsp + 32], r12
lea r15, [rip + .L__unnamed_1]
mov qword ptr [rsp + 56], r15
mov qword ptr [rsp + 64], 2
mov qword ptr [rsp + 40], 0
lea rbx, [rsp + 24]
mov qword ptr [rsp + 72], rbx
mov qword ptr [rsp + 80], 1
mov r14, qword ptr [rip + std::io::stdio::_print@GOTPCREL]
lea rdi, [rsp + 40]
call r14
movss xmm0, dword ptr [rsp + 12]
call qword ptr [rip + sinf@GOTPCREL] ; value of c calculated here
movss dword ptr [rsp + 20], xmm0
lea rax, [rsp + 20]
mov qword ptr [rsp + 24], rax
mov qword ptr [rsp + 32], r12
mov qword ptr [rsp + 56], r15
mov qword ptr [rsp + 64], 2
mov qword ptr [rsp + 40], 0
mov qword ptr [rsp + 72], rbx
mov qword ptr [rsp + 80], 1
lea rdi, [rsp + 40]
call r14
lea rax, [rsp + 12]
mov qword ptr [rsp + 24], rax
mov rax, qword ptr [rip + core::fmt::float::<impl core::fmt::Display for f32>::fmt@GOTPCREL]
mov qword ptr [rsp + 32], rax
mov qword ptr [rsp + 56], r15
mov qword ptr [rsp + 64], 2
mov qword ptr [rsp + 40], 0
mov qword ptr [rsp + 72], rbx
mov qword ptr [rsp + 80], 1
lea rdi, [rsp + 40]
call r14
add rsp, 88
pop rbx
pop r12
pop r14
pop r15
ret
.L__unnamed_2:
.L__unnamed_3:
.byte 10
.L__unnamed_1:
.quad .L__unnamed_2
.zero 8
.quad .L__unnamed_3
.asciz "\001\000\000\000\000\000\000" |
Looking at LLVM's constant folding code here it seems like it is using |
This comment was marked as resolved.
This comment was marked as resolved.
sin(0.7568418979644775390625) So the constant folded answer is the correct one, at least. (It's off by -4.25×10-8 Np, whereas 0x3f2fc6ea is off by 4.43×10-8 Np.) |
To summarize this issue: Is there any guarantee in Rust that each call to math ops like |
This is not a bug; optimizations leading to differences in the precision for these "imprecise" float operations is expected behavior. The underlying cause of this is that different libm implementations will provide different precision, so if the compiler pre-computes some results at compile time, that might yield different results than what the target would do at runtime. So, this is at most a docs-issue. IMO it should be merged with #71355.
This is our current behavior and my understanding is that it is intended that way. |
The results of libm functions must not be constant-folded, unless we're OK with miscompilations a la #124364. |
That's not necessarily true. As far as I am concerned, libm functions are non-deterministic. In that case it is okay to const-fold them even if their runtime behavior differs from the const-fold behavior. That is, for instance, how rust-lang/rfcs#3514 rationalizes const-fold producing different NaNs than what would happen at runtime. #124364 is caused by the compiler assuming that float operations are deterministic. I don't think we have evidence that LLVM assumes libm functions to be deterministic, but I am not sure. EDIT: Ah, never mind. #124364 is all about LLVM assuming that |
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
I noticed that, in certain scenarios, two consecutive
std::f32::sin()
function invocations can give two different results.A scenario where I observed this is the following:
When the
opt-level
is set to 1, the assert fails with the following output:When the
opt-level
is 0, both outputs are3f2fc6ea
, and when it is 2 or 3 both outputs are3f2fc6e9
.Another surprising thing for me is that when I remove the last println (
println!("{a}");
), the assert passes even foropt-level=1
. In that case, values are3f2fc6ea
only when theopt-level
is 0, while for other values they are3f2fc6e9
.Meta
rustc --version --verbose
:This also occurs on the following nightly version:
The text was updated successfully, but these errors were encountered: