-
Notifications
You must be signed in to change notification settings - Fork 5k
Math.FusedMultiplyAdd returns wrong results on systems without FMA3 support #98704
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
Comments
Tagging subscribers to this area: @dotnet/area-system-numerics Issue DetailsDescriptionOn systems without FMA3 instruction support (older CPUs, virtual machines with FMA3 disabled), the The documentation for the method states the following:
I would expect from this, that The rounding is correctly done if the CPU supports FMA3 in hardware. Without FMA3 support, you get different results from the same inputs. Beside being wrong, this hardware dependent change in behavior/result can lead to further issues. Reproduction StepsTo reproduce the issue, evaluate the following method on a system with a CPU without FMA3 support.
Note: Setting The input values are the following:
The correct result is
Expected behaviorThe expected return value from the method is
Note: This is as well the value returned on systems with hardware support for FMA3. Actual behaviorOn a system with a CPU without FMA3 support, the method returns the wrong value
This value is equal to
which can be obtained by wrongly rounding the exact value Regression?I have tested this on a system with dotnet-runtime-6.0.1-win-x64 and with dotnet-runtime-8.0.2-win-x64. The issue is present for both versions. Known WorkaroundsThe only (known) workaround is to check the flag
and if it is https://git.musl-libc.org/cgit/musl/tree/src/math/fma.c ConfigurationTested .NET versions see, above. Tested on Windows 7 and Windows 10 operating systems. Other informationOther input values that produce wrong results on systems without FMA3 support:
|
Can you clarify what operating system you're running against? FMA simply defers down to the C runtime if hardware acceleration is not available. So my best guess is that there is potentially a bug in the underlying FMA algorithm used by the C runtime for whichever OS you've mentioned. |
I have tested this on Windows 7 and Windows 10. I'm not sure which method in which dll finally gets called for the software fallback, but I suspect it is Based on the documentation https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fma-fmaf-fmal?view=msvc-170 and another bug report for it https://developercommunity.visualstudio.com/t/C-std::fma-returns-incorrect-result/242309 I get the impression, that this is not really a complete software implementation of |
Well, that's definitely a bug, the C specification requires that |
I've opened a new bug against MSVC here: https://developercommunity.visualstudio.com/t/MSVCs-fma-implementation-is-incorrect-o/10594003. It covers the IEEE 754 and C Programing Language specification requirements here. |
Description
On systems without FMA3 instruction support (older CPUs, virtual machines with FMA3 disabled), the
Math.FusedMultiplyAdd
method returns incorrectly rounded results.The documentation for the method states the following:
I would expect from this, that
rounds to the nearest representable value
is the same for arithmetic operations and theMath.FusedMultiplyAdd
operation. That means, it is rounded to thenearest representable value (ties to even)
.The rounding is correctly done if the CPU supports FMA3 in hardware. Without FMA3 support, you get different results from the same inputs. Beside being wrong, this hardware dependent change in behavior/result can lead to further issues.
Reproduction Steps
To reproduce the issue, evaluate the following method on a system with a CPU without FMA3 support.
Note: Setting
COMPlus_EnableFMA=0
is not sufficient to reproduce the problem. The flag does not affect the chosen code path if hardware FMA3 is available. The only (known) way to reproduce it is by using a CPU without FMA3 or a system virtualized with VirtualBox (which does not expose/support FMA3 for the client system).The input values are the following:
The correct result is
Expected behavior
The expected return value from the method is
Note: This is as well the value returned on systems with hardware support for FMA3.
Actual behavior
On a system with a CPU without FMA3 support, the method returns the wrong value
This value is equal to
which can be obtained by wrongly rounding the exact value
1 + 2^-1 + 2^-53
to the next odd least significant bit instead of rounding to the next even least significant bit.Regression?
I have tested this on a system with dotnet-runtime-6.0.1-win-x64 and with dotnet-runtime-8.0.2-win-x64. The issue is present for both versions.
Known Workarounds
The only (known) workaround is to check the flag
and if it is
false
to call another software implementation ofFusedMultiplyAdd
, for example a translation of the codehttps://git.musl-libc.org/cgit/musl/tree/src/math/fma.c
Configuration
Tested .NET versions see, above. Tested on Windows 7 and Windows 10 operating systems.
Other information
Other input values that produce wrong results on systems without FMA3 support:
The text was updated successfully, but these errors were encountered: