-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
INumber.Min(+QNaN, 1)
returns 1
#98285
Comments
Tagging subscribers to this area: @dotnet/area-system-numerics Issue Detailsfloat qNaN = BitConverter.Int32BitsToSingle(0x7FC00000);
Console.WriteLine(float.Min(qNaN, 1));
runtime/src/libraries/System.Private.CoreLib/src/System/Numerics/INumber.cs Lines 108 to 127 in 9699f39
(another issue: search
|
Can you please share a minimal repro showing the problem? |
This issue has been marked |
The output should be using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Numerics;
float qNaN = BitConverter.Int32BitsToSingle(0x7FC00000);
Console.WriteLine(new Calculator<float>().Min(qNaN, 1f));
Console.WriteLine(new Calculator<NumberWrapper<float>>().Min(qNaN, 1f));
class Calculator<T> where T : INumber<T>
{
public T Min(T x, T y) => T.Min(x, y);
}
struct NumberWrapper<T> : INumber<NumberWrapper<T>> where T : INumber<T>
{
public T Value;
public NumberWrapper(T value) => Value = value;
public static implicit operator NumberWrapper<T>(T value) => new NumberWrapper<T>(value);
public static implicit operator T(NumberWrapper<T> value) => value.Value;
public static NumberWrapper<T> One => T.One;
public static int Radix => T.Radix;
public static NumberWrapper<T> Zero => T.Zero;
public static NumberWrapper<T> AdditiveIdentity => T.AdditiveIdentity;
public static NumberWrapper<T> MultiplicativeIdentity => T.MultiplicativeIdentity;
public static NumberWrapper<T> Abs(NumberWrapper<T> value) => T.Abs(value);
public static bool IsCanonical(NumberWrapper<T> value) => T.IsCanonical(value);
public static bool IsComplexNumber(NumberWrapper<T> value) => T.IsComplexNumber(value);
public static bool IsEvenInteger(NumberWrapper<T> value) => T.IsEvenInteger(value);
public static bool IsFinite(NumberWrapper<T> value) => T.IsFinite(value);
public static bool IsImaginaryNumber(NumberWrapper<T> value) => T.IsImaginaryNumber(value);
public static bool IsInfinity(NumberWrapper<T> value) => T.IsInfinity(value);
public static bool IsInteger(NumberWrapper<T> value) => T.IsInteger(value);
public static bool IsNaN(NumberWrapper<T> value) => T.IsNaN(value);
public static bool IsNegative(NumberWrapper<T> value) => T.IsNegative(value);
public static bool IsNegativeInfinity(NumberWrapper<T> value) => T.IsNegativeInfinity(value);
public static bool IsNormal(NumberWrapper<T> value) => T.IsNormal(value);
public static bool IsOddInteger(NumberWrapper<T> value) => T.IsOddInteger(value);
public static bool IsPositive(NumberWrapper<T> value) => T.IsPositive(value);
public static bool IsPositiveInfinity(NumberWrapper<T> value) => T.IsPositiveInfinity(value);
public static bool IsRealNumber(NumberWrapper<T> value) => T.IsRealNumber(value);
public static bool IsSubnormal(NumberWrapper<T> value) => T.IsSubnormal(value);
public static bool IsZero(NumberWrapper<T> value) => T.IsZero(value);
public static NumberWrapper<T> MaxMagnitude(NumberWrapper<T> x, NumberWrapper<T> y) => T.MaxMagnitude(x, y);
public static NumberWrapper<T> MaxMagnitudeNumber(NumberWrapper<T> x, NumberWrapper<T> y) => T.MaxMagnitudeNumber(x, y);
public static NumberWrapper<T> MinMagnitude(NumberWrapper<T> x, NumberWrapper<T> y) => T.MinMagnitude(x, y);
public static NumberWrapper<T> MinMagnitudeNumber(NumberWrapper<T> x, NumberWrapper<T> y) => T.MinMagnitudeNumber(x, y);
public static NumberWrapper<T> Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider) => T.Parse(s, style, provider);
public static NumberWrapper<T> Parse(string s, NumberStyles style, IFormatProvider? provider) => T.Parse(s, style, provider);
public static NumberWrapper<T> Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => T.Parse(s, provider);
public static NumberWrapper<T> Parse(string s, IFormatProvider? provider) => T.Parse(s, provider);
public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out NumberWrapper<T> result)
{
var succeeded = T.TryParse(s, style, provider, out T actualResult);
result = actualResult;
return succeeded;
}
public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, [MaybeNullWhen(false)] out NumberWrapper<T> result)
{
var succeeded = T.TryParse(s, style, provider, out T actualResult);
result = actualResult;
return succeeded;
}
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, [MaybeNullWhen(false)] out NumberWrapper<T> result)
{
var succeeded = T.TryParse(s, provider, out T actualResult);
result = actualResult;
return succeeded;
}
public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out NumberWrapper<T> result)
{
var succeeded = T.TryParse(s, provider, out T actualResult);
result = actualResult;
return succeeded;
}
public int CompareTo(object? obj)
{
if (obj is not NumberWrapper<T> other)
{
return (obj is null) ? 1 : throw new ArgumentException();
}
return CompareTo(other);
}
public int CompareTo(NumberWrapper<T> other) => Value.CompareTo(other.Value);
public override bool Equals([NotNullWhen(true)] object? obj) => (obj is NumberWrapper<T> other) && Equals(other);
public bool Equals(NumberWrapper<T> other) => Value.Equals(other.Value);
public override int GetHashCode() => Value.GetHashCode();
public string ToString(string? format, IFormatProvider? formatProvider) => Value.ToString(format, formatProvider);
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => Value.TryFormat(destination, out charsWritten, format, provider);
static bool INumberBase<NumberWrapper<T>>.TryConvertFromChecked<TOther>(TOther value, out NumberWrapper<T> result)
{
bool succeeded = T.TryConvertFromChecked(value, out T actualResult);
result = actualResult;
return succeeded;
}
static bool INumberBase<NumberWrapper<T>>.TryConvertFromSaturating<TOther>(TOther value, out NumberWrapper<T> result)
{
bool succeeded = T.TryConvertFromSaturating(value, out T actualResult);
result = actualResult;
return succeeded;
}
static bool INumberBase<NumberWrapper<T>>.TryConvertFromTruncating<TOther>(TOther value, out NumberWrapper<T> result)
{
bool succeeded = T.TryConvertFromTruncating(value, out T actualResult);
result = actualResult;
return succeeded;
}
static bool INumberBase<NumberWrapper<T>>.TryConvertToChecked<TOther>(NumberWrapper<T> value, out TOther result) => T.TryConvertToChecked(value, out result);
static bool INumberBase<NumberWrapper<T>>.TryConvertToSaturating<TOther>(NumberWrapper<T> value, out TOther result) => T.TryConvertToSaturating(value, out result);
static bool INumberBase<NumberWrapper<T>>.TryConvertToTruncating<TOther>(NumberWrapper<T> value, out TOther result) => T.TryConvertToTruncating(value, out result);
public static NumberWrapper<T> operator +(NumberWrapper<T> value) => +value.Value;
public static NumberWrapper<T> operator +(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value + right.Value;
public static NumberWrapper<T> operator -(NumberWrapper<T> value) => -value.Value;
public static NumberWrapper<T> operator -(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value - right.Value;
public static NumberWrapper<T> operator ++(NumberWrapper<T> value) => value.Value++;
public static NumberWrapper<T> operator --(NumberWrapper<T> value) => value.Value--;
public static NumberWrapper<T> operator *(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value * right.Value;
public static NumberWrapper<T> operator /(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value / right.Value;
public static NumberWrapper<T> operator %(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value % right.Value;
public static bool operator ==(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value == right.Value;
public static bool operator !=(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value != right.Value;
public static bool operator <(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value > right.Value;
public static bool operator >(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value < right.Value;
public static bool operator <=(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value <= right.Value;
public static bool operator >=(NumberWrapper<T> left, NumberWrapper<T> right) => left.Value >= right.Value;
} |
Did you purposefully implement < and > incorrectly?
? |
But, yes, the Min implementation does look a bit off. |
No, it's a mistake. Interesting, I copied them from Lines 391 to 392 in 6299d3e
|
Double/Single/Half.Min(+QNaN, 1)
correctly returns NaN butINumber.Min
not:runtime/src/libraries/System.Private.CoreLib/src/System/Numerics/INumber.cs
Lines 108 to 127 in 9699f39
(another issue: search
..
inINumber.cs
to find a redundant dot)The text was updated successfully, but these errors were encountered: