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

Roslyn and .Net disagree about converting double.NaN to long #72526

Closed
svick opened this issue Mar 13, 2024 · 4 comments
Closed

Roslyn and .Net disagree about converting double.NaN to long #72526

svick opened this issue Mar 13, 2024 · 4 comments
Labels
Area-Compilers Question Resolution-Answered The question has been answered untriaged Issues and PRs which have not yet been triaged by a lead

Comments

@svick
Copy link
Contributor

svick commented Mar 13, 2024

Version Used: .Net 8

Steps to Reproduce:

Compile and run the following code:

double d = double.NaN;
Console.WriteLine((long)d);

Console.WriteLine(unchecked((long)double.NaN));

Expected Behavior:

Both versions produce the same output.

Actual Behavior:

The output is:

-9223372036854775808
0

I.e. when .Net converts double.NaN to long at run-time, the result is long.MinValue. But when Roslyn performs an unchecked conversion of a constant double.NaN to long at compile-time, the result is 0.

I don't know if this is an issue in Roslyn, in the .Net runtime, or if the inconsistency is expected, but I thought it would be worth reporting nevertheless.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Mar 13, 2024
@RikkiGibson
Copy link
Contributor

@tannergooding might have insight about what should happen here.

@tannergooding
Copy link
Member

tannergooding commented Mar 13, 2024

As per the IEEE 754 specification, conversion of floating-point values to integers where the input is either not a finite value (NaN or `Infinity) or where the rounded integer result is not representable in the destination format (would be greater than MaxValue or less than MinValue) is effectively "implementation defined".

What this ultimately means is that every platform has historically done a different behavior and in order for C# to allow constant folding and determinism, it picked a format that worked for it when these edge cases are encountered.

The .NET runtime is moving towards normalizing its behavior across platforms as well: dotnet/runtime#61885

The behavior we standardized on is the behavior that fits in with other platforms (such as Arm64), that is required by certain platforms (such as WASM), and which fits into the general intent of the IEEE 754 floating-point specification with regards to operations. The general intent (and requirement for most operations) is that results are taken as given, computed as if to infinite precision and unbounded range, and then rounded to the nearest representable result.

Thus, the behavior the runtime is normalizing on is that float to integer conversions "saturate". Thus, (long)float.MaxValue should return long.MaxValue and (long)float.MinValue should return long.MinValue (same for other types like int, uint, or ulong). This then leaves the handling for NaN, for which the generally agreed upon behavior is to return 0 (there are various reasons for this, including how it plays into the intended use with Complex numbers).

Roslyn currently matches the intended behavior for NaN. It does not match the long term intended behavior for other overflowing results, where it also returns 0. But until the behavior is normalized, it's not an overly large concern as you can already get different results across platforms and across other considerations (such as conversion to a small type like byte, sbyte, short, or ushort, where its truncating the int output)

@svick
Copy link
Contributor Author

svick commented Mar 14, 2024

@tannergooding Thanks for the explanation.

@RikkiGibson
Copy link
Contributor

Thanks @tannergooding! I will close out as it looks like the question has been answered.

@RikkiGibson RikkiGibson added Question Resolution-Answered The question has been answered labels Mar 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Question Resolution-Answered The question has been answered untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

No branches or pull requests

3 participants