dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.25k stars 4.73k forks source link

[API Proposal]: MinSafeInteger and MaxSafeInteger constants for System.Single and System.Double #108055

Open scharnyw opened 1 month ago

scharnyw commented 1 month ago

Background and motivation

I find it occasionally necessary to represent integral values with floating-point numeric types. Some reasons why this may be necessary include, but are not limited to:

  1. Compatibility with legacy code
  2. A need to represent infinities and/or NaN with integral values
  3. Desire to use a single field to hold a value that could be integral or floating-point, depending on the scenario

In such cases it would be helpful to have the constants MinSafeInteger and MaxSafeInteger defined in the floating-point numeric types to know if an integral value could be represented safely in the given type. "Safely" in this context refers to the ability to represent integers exactly and to compare them correctly.

This proposal is identical in concept to the corresponding APIs in JavaScript.

API Proposal

namespace System;

public readonly struct Double
{
    public const double MinSafeInteger = -9007199254740991d; // -(2^53-1)
    public const double MaxSafeInteger = 9007199254740991d; // 2^53-1
}

public readonly struct Single
{
    public const double MinSafeInteger = -16777215f; // -(2^24-1)
    public const double MaxSafeInteger = 16777215f; // 2^24-1
}

API Usage

double value = ...;

if (value >= double.MinSafeInteger && value <= double.MaxSafeInteger)
{
    // value can safely be represented in double
}
else
{
    // nope
}

Alternative Designs

No response

Risks

No response

dotnet-policy-service[bot] commented 1 month ago

Tagging subscribers to this area: @dotnet/area-system-numerics See info in area-owners.md if you want to be subscribed.

huoyaoyuan commented 1 month ago

The values can be exposed by IFloatingPoint interface.

Note that the usage contains a pitfall. If you convert the value from the integer than testing with Max/MinSafeInteger, you may get MaxSafeInteger+1 rounded to MaxSafeInteger.

scharnyw commented 1 month ago

Note that the usage contains a pitfall. If you convert the value from the integer than testing with Max/MinSafeInteger, you may get MaxSafeInteger+1 rounded to MaxSafeInteger.

I believe you won't, because MaxSafeInteger is not the maximum integer such that it and all smaller integers can be represented exactly in the floating point format. It is the maximum integer such that it can be represented exactly and can be compared correctly against all other integers. The latter is smaller than the former by one, i.e. for doubles, the former is 2^53 while the latter is 2^53-1.

Therefore both MaxSafeInteger and MaxSafeInteger + 1 can be represented exactly in doubles, so pitfalls like this don't happen.