-
Notifications
You must be signed in to change notification settings - Fork 5k
Arm64: Casting a specific double value to uint32 caused an unexpected divide by zero to occur #95290
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 .NET6, on an arm64 processor, a cast from large negative double to uint32 caused a value to be zero. The flag Reproduction StepsIn a unit test on the arm64 environment we used, this C# code will produce the bug.
Workaround. We cast to int32 first, then uint32 after:
Expected behaviorThis double cast into uint32 should result in this number:
Actual behavior
Regression?N/A Known WorkaroundsCast to int first:
ConfigurationThis is on an 80 core Neoverse-N1 running Rocky 9.2 with .NET 6 sdk. https://www.arm.com/products/silicon-ip-cpu/neoverse/neoverse-n1
80 total processors. Here's the first one:
On the same OS, we run a container in podman with Ubuntu 22 container OS, and the same error occurs.
OS release:
Other informationNo response
|
This is by design, ARM64 saturates when converting floating point numbers to integers and it's planned to mimic this behaviour on X64 (and other platforms) in .NET 9 too. |
Ah good! It's consistent with C++ code too. On the same arm64 server, create this
|
Looks like something we can close as not an issue, at least in .NET6 |
Most languages do not define a behavior for overflow of floating-point to integral conversions. This is namely because IEEE 754 does not define a behavior. Accordingly, different compilers (MSVC vs Clang vs GCC vs ...) and different languages (C# vs C++ vs Rust vs ...) may do different things. In many cases these languages have one behavior for constant folding and another behavior for when the value is unknown. When the value is unknown they often defer to the underlying platform. Thus you can get different results for constant folding between Arm64 and x64 depending on which your compiler is running on. You can likewise get different results for Newer languages have started prescribing a particular behavior to avoid these cross platform differences. For example, WASM requires that the behavior saturate (but leaves the handling for NaN as undefined). Rust also requires saturation and requires NaN to convert to 0. .NET plans on also having deterministic behavior long term (tracked by #61885) and we hope to complete this work in .NET 9. We will match what Rust does (which is also what Arm64 does and what the new x64 instructions being exposed in AVX10 will do) and to saturate, with NaN converting to 0. This likewise matches, conceptually, the IEEE 754 rules that exist for operations in general; which is that results are computed as if to infinite precision and unbounded range and then rounded, using the target rounding mode, to the nearest representable result. This means that out of range values would round to Max and Min for the given type, respectively. Until that work is complete, you will have to manually handle these edge cases if that's important to you. |
This issue has been marked |
Excellent explanation. Thanks for the effort. |
Uh oh!
There was an error while loading. Please reload this page.
Description
On .NET6, on an arm64 processor, a cast from large negative double to uint32 caused a value to be zero.
In other casting situations on arm64 and on x86, it was not zero.
It later resulted in divide by zero errors.
The flag
--runtime linux-arm64
doesn't effect the problem, as it occurs with and without it.Reproduction Steps
In a unit test on the arm64 environment we used, this C# code will produce the bug.
Unclear if this occurs on other processors, operating systems, dotnet runtime environments.
Workaround. We cast to int32 first, then uint32 after:
Expected behavior
This double cast into uint32 should result in this number:
Actual behavior
Regression?
N/A
Known Workarounds
Cast to int first:
Configuration
This is on an 80 core Neoverse-N1 running Rocky 9.2 with .NET 6 sdk.
https://www.arm.com/products/silicon-ip-cpu/neoverse/neoverse-n1
80 total processors. Here's the first one:
On the same OS, we run a container in podman with Ubuntu 22 container OS, and the same error occurs.
How we can run in podman. After logging into the bash prompt, run the dotnet test command on that specific DLL with the unit test and filter for it.
OS release:
Other information
No response
The text was updated successfully, but these errors were encountered: