|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace System.Numerics
{
/// <summary>Defines a number type.</summary>
/// <typeparam name="TSelf">The type that implements the interface.</typeparam>
public interface INumber<TSelf>
: IComparable,
IComparable<TSelf>,
IComparisonOperators<TSelf, TSelf, bool>,
IModulusOperators<TSelf, TSelf, TSelf>,
INumberBase<TSelf>
where TSelf : INumber<TSelf>?
{
/// <summary>Clamps a value to an inclusive minimum and maximum value.</summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The inclusive minimum to which <paramref name="value" /> should clamp.</param>
/// <param name="max">The inclusive maximum to which <paramref name="value" /> should clamp.</param>
/// <returns>The result of clamping <paramref name="value" /> to the inclusive range of <paramref name="min" /> and <paramref name="max" />.</returns>
/// <exception cref="ArgumentException"><paramref name="min" /> is greater than <paramref name="max" />.</exception>
static virtual TSelf Clamp(TSelf value, TSelf min, TSelf max)
{
if (min > max)
{
Math.ThrowMinMaxException(min, max);
}
TSelf result = value;
result = TSelf.Max(result, min);
result = TSelf.Min(result, max);
return result;
}
/// <summary>Clamps a value to an inclusive minimum and maximum value using platform-specific behavior for <c>NaN</c> and <c>NegativeZero</c>.</summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The inclusive minimum to which <paramref name="value" /> should clamp.</param>
/// <param name="max">The inclusive maximum to which <paramref name="value" /> should clamp.</param>
/// <returns>The result of clamping <paramref name="value" /> to the inclusive range of <paramref name="min" /> and <paramref name="max" />.</returns>
/// <exception cref="ArgumentException"><paramref name="min" /> is greater than <paramref name="max" />.</exception>
static virtual TSelf ClampNative(TSelf value, TSelf min, TSelf max)
{
if (min > max)
{
Math.ThrowMinMaxException(min, max);
}
TSelf result = value;
result = TSelf.MaxNative(result, min);
result = TSelf.MinNative(result, max);
return result;
}
/// <summary>Copies the sign of a value to the sign of another value.</summary>
/// <param name="value">The value whose magnitude is used in the result.</param>
/// <param name="sign">The value whose sign is used in the result.</param>
/// <returns>A value with the magnitude of <paramref name="value" /> and the sign of <paramref name="sign" />.</returns>
static virtual TSelf CopySign(TSelf value, TSelf sign)
{
TSelf result = value;
if (TSelf.IsNegative(value) != TSelf.IsNegative(sign))
{
result = checked(-result);
}
return result;
}
/// <summary>Compares two values to compute which is greater.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is greater than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
/// <remarks>For <see cref="IFloatingPoint{TSelf}" /> this method matches the IEEE 754:2019 <c>maximum</c> function. This requires NaN inputs to be propagated back to the caller and for <c>-0.0</c> to be treated as less than <c>+0.0</c>.</remarks>
static virtual TSelf Max(TSelf x, TSelf y)
{
// This matches the IEEE 754:2019 `maximum` function
//
// It propagates NaN inputs back to the caller and
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.
if (x != y)
{
if (!TSelf.IsNaN(x))
{
return y < x ? x : y;
}
return x;
}
return TSelf.IsNegative(y) ? x : y;
}
/// <summary>Compares two values to compute which is greater using platform-specific behavior for <c>NaN</c> and <c>NegativeZero</c>.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is greater than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
static virtual TSelf MaxNative(TSelf x, TSelf y)
{
return (x > y) ? x : y;
}
/// <summary>Compares two values to compute which is greater and returning the other value if an input is <c>NaN</c>.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is greater than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
/// <remarks>For <see cref="IFloatingPoint{TSelf}" /> this method matches the IEEE 754:2019 <c>maximumNumber</c> function. This requires NaN inputs to not be propagated back to the caller and for <c>-0.0</c> to be treated as less than <c>+0.0</c>.</remarks>
static virtual TSelf MaxNumber(TSelf x, TSelf y)
{
// This matches the IEEE 754:2019 `maximumNumber` function
//
// It does not propagate NaN inputs back to the caller and
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.
if (x != y)
{
if (!TSelf.IsNaN(y))
{
return y < x ? x : y;
}
return x;
}
return TSelf.IsNegative(y) ? x : y;
}
/// <summary>Compares two values to compute which is lesser.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is less than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
/// <remarks>For <see cref="IFloatingPoint{TSelf}" /> this method matches the IEEE 754:2019 <c>minimum</c> function. This requires NaN inputs to be propagated back to the caller and for <c>-0.0</c> to be treated as less than <c>+0.0</c>.</remarks>
static virtual TSelf Min(TSelf x, TSelf y)
{
// This matches the IEEE 754:2019 `minimum` function
//
// It propagates NaN inputs back to the caller and
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.
if (x != y)
{
if (!TSelf.IsNaN(x))
{
return x < y ? x : y;
}
return x;
}
return TSelf.IsNegative(x) ? x : y;
}
/// <summary>Compares two values to compute which is lesser using platform-specific behavior for <c>NaN</c> and <c>NegativeZero</c>.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is lesser than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
static virtual TSelf MinNative(TSelf x, TSelf y)
{
return (x < y) ? x : y;
}
/// <summary>Compares two values to compute which is lesser and returning the other value if an input is <c>NaN</c>.</summary>
/// <param name="x">The value to compare with <paramref name="y" />.</param>
/// <param name="y">The value to compare with <paramref name="x" />.</param>
/// <returns><paramref name="x" /> if it is less than <paramref name="y" />; otherwise, <paramref name="y" />.</returns>
/// <remarks>For <see cref="IFloatingPoint{TSelf}" /> this method matches the IEEE 754:2019 <c>minimumNumber</c> function. This requires NaN inputs to not be propagated back to the caller and for <c>-0.0</c> to be treated as less than <c>+0.0</c>.</remarks>
static virtual TSelf MinNumber(TSelf x, TSelf y)
{
// This matches the IEEE 754:2019 `minimumNumber` function
//
// It does not propagate NaN inputs back to the caller and
// otherwise returns the larger of the inputs. It
// treats +0 as larger than -0 as per the specification.
if (x != y)
{
if (!TSelf.IsNaN(y))
{
return x < y ? x : y;
}
return x;
}
return TSelf.IsNegative(x) ? x : y;
}
/// <summary>Computes the sign of a value.</summary>
/// <param name="value">The value whose sign is to be computed.</param>
/// <returns>A positive value if <paramref name="value" /> is positive, <c>0</c> if <paramref name="value" /> is zero, and a negative value if <paramref name="value" /> is negative.</returns>
/// <remarks>It is recommended that a function return <c>1</c>, <c>0</c>, and <c>-1</c>, respectively.</remarks>
static virtual int Sign(TSelf value)
{
if (value != TSelf.Zero)
{
if (TSelf.IsNaN(value))
{
ThrowHelper.ThrowArithmeticException(SR.Arithmetic_NaN);
}
return TSelf.IsNegative(value) ? -1 : +1;
}
return 0;
}
}
}
|