Skip to content

Commit 26b58b9

Browse files
Add Lerp to IFloatingPointIeee754 (#81186)
* Add Lerp to IFloatingPointIeee754 * Add tests covering Lerp * Fix build error * Handle negative zero
1 parent daeb683 commit 26b58b9

File tree

11 files changed

+220
-0
lines changed

11 files changed

+220
-0
lines changed

src/libraries/System.Private.CoreLib/src/System/Double.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,9 @@ bool IFloatingPoint<double>.TryWriteSignificandLittleEndian(Span<byte> destinati
832832
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ILogB(TSelf)" />
833833
public static int ILogB(double x) => Math.ILogB(x);
834834

835+
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Lerp(TSelf, TSelf, TSelf)" />
836+
public static double Lerp(double value1, double value2, double amount) => (value1 * (1.0 - amount)) + (value2 * amount);
837+
835838
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ReciprocalEstimate(TSelf)" />
836839
public static double ReciprocalEstimate(double x) => Math.ReciprocalEstimate(x);
837840

src/libraries/System.Private.CoreLib/src/System/Half.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,9 @@ public static Half BitIncrement(Half x)
13211321
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ILogB(TSelf)" />
13221322
public static int ILogB(Half x) => MathF.ILogB((float)x);
13231323

1324+
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Lerp(TSelf, TSelf, TSelf)" />
1325+
public static Half Lerp(Half value1, Half value2, Half amount) => (Half)float.Lerp((float)value1, (float)value2, (float)amount);
1326+
13241327
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ReciprocalEstimate(TSelf)" />
13251328
public static Half ReciprocalEstimate(Half x) => (Half)MathF.ReciprocalEstimate((float)x);
13261329

src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ public interface IFloatingPointIeee754<TSelf>
7272
/// <returns>The integer logarithm of <paramref name="x" />.</returns>
7373
static abstract int ILogB(TSelf x);
7474

75+
/// <summary>Performs a linear interpolation between two values based on the given weight.</summary>
76+
/// <param name="value1">The first value, which is intended to be the lower bound.</param>
77+
/// <param name="value2">The second value, which is intended to be the upper bound.</param>
78+
/// <param name="amount">A value, intended to be between 0 and 1, that indicates the weight of the interpolation.</param>
79+
/// <returns>The interpolated value.</returns>
80+
/// <remarks>This method presumes inputs are well formed and does not validate that <c>value1 &lt; value2</c> nor that <c>0 &lt;= amount &lt;= 1</c>.</remarks>
81+
static virtual TSelf Lerp(TSelf value1, TSelf value2, TSelf amount) => (value1 * (TSelf.One - amount)) + (value2 * amount);
82+
7583
/// <summary>Computes an estimate of the reciprocal of a value.</summary>
7684
/// <param name="x">The value whose estimate of the reciprocal is to be computed.</param>
7785
/// <returns>An estimate of the reciprocal of <paramref name="x" />.</returns>

src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NFloat.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,9 @@ bool IFloatingPoint<NFloat>.TryWriteSignificandLittleEndian(Span<byte> destinati
11641164
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ILogB(TSelf)" />
11651165
public static int ILogB(NFloat x) => NativeType.ILogB(x._value);
11661166

1167+
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Lerp(TSelf, TSelf, TSelf)" />
1168+
public static NFloat Lerp(NFloat value1, NFloat value2, NFloat amount) => new NFloat(NativeType.Lerp(value1._value, value2._value, amount._value));
1169+
11671170
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ReciprocalEstimate(TSelf)" />
11681171
public static NFloat ReciprocalEstimate(NFloat x) => new NFloat(NativeType.ReciprocalEstimate(x._value));
11691172

src/libraries/System.Private.CoreLib/src/System/Single.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,9 @@ bool IFloatingPoint<float>.TryWriteSignificandLittleEndian(Span<byte> destinatio
812812
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ILogB(TSelf)" />
813813
public static int ILogB(float x) => MathF.ILogB(x);
814814

815+
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.Lerp(TSelf, TSelf, TSelf)" />
816+
public static float Lerp(float value1, float value2, float amount) => (value1 * (1.0f - amount)) + (value2 * amount);
817+
815818
/// <inheritdoc cref="IFloatingPointIeee754{TSelf}.ReciprocalEstimate(TSelf)" />
816819
public static float ReciprocalEstimate(float x) => MathF.ReciprocalEstimate(x);
817820

src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,7 @@ public static void Free(void* ptr) { }
11751175
public static bool IsPow2(System.Runtime.InteropServices.NFloat value) { throw null; }
11761176
public static bool IsRealNumber(System.Runtime.InteropServices.NFloat value) { throw null; }
11771177
public static bool IsSubnormal(System.Runtime.InteropServices.NFloat value) { throw null; }
1178+
public static System.Runtime.InteropServices.NFloat Lerp(System.Runtime.InteropServices.NFloat value1, System.Runtime.InteropServices.NFloat value2, System.Runtime.InteropServices.NFloat amount) { throw null; }
11781179
public static System.Runtime.InteropServices.NFloat Log(System.Runtime.InteropServices.NFloat x) { throw null; }
11791180
public static System.Runtime.InteropServices.NFloat Log(System.Runtime.InteropServices.NFloat x, System.Runtime.InteropServices.NFloat newBase) { throw null; }
11801181
public static System.Runtime.InteropServices.NFloat Log10(System.Runtime.InteropServices.NFloat x) { throw null; }

src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/NFloatTests.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,5 +2469,81 @@ public static void TanPiTest64(double value, double expectedResult, double allow
24692469
AssertExtensions.Equal(-expectedResult, NFloat.TanPi((NFloat)(-value)), allowedVariance);
24702470
AssertExtensions.Equal(+expectedResult, NFloat.TanPi((NFloat)(+value)), allowedVariance);
24712471
}
2472+
2473+
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is32BitProcess))]
2474+
[InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.5f, float.NegativeInfinity)]
2475+
[InlineData(float.NegativeInfinity, float.NaN, 0.5f, float.NaN)]
2476+
[InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.5f, float.NaN)]
2477+
[InlineData(float.NegativeInfinity, 0.0f, 0.5f, float.NegativeInfinity)]
2478+
[InlineData(float.NegativeInfinity, 1.0f, 0.5f, float.NegativeInfinity)]
2479+
[InlineData(float.NaN, float.NegativeInfinity, 0.5f, float.NaN)]
2480+
[InlineData(float.NaN, float.NaN, 0.5f, float.NaN)]
2481+
[InlineData(float.NaN, float.PositiveInfinity, 0.5f, float.NaN)]
2482+
[InlineData(float.NaN, 0.0f, 0.5f, float.NaN)]
2483+
[InlineData(float.NaN, 1.0f, 0.5f, float.NaN)]
2484+
[InlineData(float.PositiveInfinity, float.NegativeInfinity, 0.5f, float.NaN)]
2485+
[InlineData(float.PositiveInfinity, float.NaN, 0.5f, float.NaN)]
2486+
[InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.5f, float.PositiveInfinity)]
2487+
[InlineData(float.PositiveInfinity, 0.0f, 0.5f, float.PositiveInfinity)]
2488+
[InlineData(float.PositiveInfinity, 1.0f, 0.5f, float.PositiveInfinity)]
2489+
[InlineData(1.0f, 3.0f, 0.0f, 1.0f)]
2490+
[InlineData(1.0f, 3.0f, 0.5f, 2.0f)]
2491+
[InlineData(1.0f, 3.0f, 1.0f, 3.0f)]
2492+
[InlineData(1.0f, 3.0f, 2.0f, 5.0f)]
2493+
[InlineData(2.0f, 4.0f, 0.0f, 2.0f)]
2494+
[InlineData(2.0f, 4.0f, 0.5f, 3.0f)]
2495+
[InlineData(2.0f, 4.0f, 1.0f, 4.0f)]
2496+
[InlineData(2.0f, 4.0f, 2.0f, 6.0f)]
2497+
[InlineData(3.0f, 1.0f, 0.0f, 3.0f)]
2498+
[InlineData(3.0f, 1.0f, 0.5f, 2.0f)]
2499+
[InlineData(3.0f, 1.0f, 1.0f, 1.0f)]
2500+
[InlineData(3.0f, 1.0f, 2.0f, -1.0f)]
2501+
[InlineData(4.0f, 2.0f, 0.0f, 4.0f)]
2502+
[InlineData(4.0f, 2.0f, 0.5f, 3.0f)]
2503+
[InlineData(4.0f, 2.0f, 1.0f, 2.0f)]
2504+
[InlineData(4.0f, 2.0f, 2.0f, 0.0f)]
2505+
public static void LerpTest32(float value1, float value2, float amount, float expectedResult)
2506+
{
2507+
AssertExtensions.Equal(+expectedResult, (float)NFloat.Lerp(+value1, +value2, amount), 0);
2508+
AssertExtensions.Equal((expectedResult == 0.0f) ? expectedResult : -expectedResult, (float)NFloat.Lerp(-value1, -value2, amount), 0);
2509+
}
2510+
2511+
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
2512+
[InlineData(double.NegativeInfinity, double.NegativeInfinity, 0.5, double.NegativeInfinity)]
2513+
[InlineData(double.NegativeInfinity, double.NaN, 0.5, double.NaN)]
2514+
[InlineData(double.NegativeInfinity, double.PositiveInfinity, 0.5, double.NaN)]
2515+
[InlineData(double.NegativeInfinity, 0.0, 0.5, double.NegativeInfinity)]
2516+
[InlineData(double.NegativeInfinity, 1.0, 0.5, double.NegativeInfinity)]
2517+
[InlineData(double.NaN, double.NegativeInfinity, 0.5, double.NaN)]
2518+
[InlineData(double.NaN, double.NaN, 0.5, double.NaN)]
2519+
[InlineData(double.NaN, double.PositiveInfinity, 0.5, double.NaN)]
2520+
[InlineData(double.NaN, 0.0, 0.5, double.NaN)]
2521+
[InlineData(double.NaN, 1.0, 0.5, double.NaN)]
2522+
[InlineData(double.PositiveInfinity, double.NegativeInfinity, 0.5, double.NaN)]
2523+
[InlineData(double.PositiveInfinity, double.NaN, 0.5, double.NaN)]
2524+
[InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.5, double.PositiveInfinity)]
2525+
[InlineData(double.PositiveInfinity, 0.0, 0.5, double.PositiveInfinity)]
2526+
[InlineData(double.PositiveInfinity, 1.0, 0.5, double.PositiveInfinity)]
2527+
[InlineData(1.0, 3.0, 0.0, 1.0)]
2528+
[InlineData(1.0, 3.0, 0.5, 2.0)]
2529+
[InlineData(1.0, 3.0, 1.0, 3.0)]
2530+
[InlineData(1.0, 3.0, 2.0, 5.0)]
2531+
[InlineData(2.0, 4.0, 0.0, 2.0)]
2532+
[InlineData(2.0, 4.0, 0.5, 3.0)]
2533+
[InlineData(2.0, 4.0, 1.0, 4.0)]
2534+
[InlineData(2.0, 4.0, 2.0, 6.0)]
2535+
[InlineData(3.0, 1.0, 0.0, 3.0)]
2536+
[InlineData(3.0, 1.0, 0.5, 2.0)]
2537+
[InlineData(3.0, 1.0, 1.0, 1.0)]
2538+
[InlineData(3.0, 1.0, 2.0, -1.0)]
2539+
[InlineData(4.0, 2.0, 0.0, 4.0)]
2540+
[InlineData(4.0, 2.0, 0.5, 3.0)]
2541+
[InlineData(4.0, 2.0, 1.0, 2.0)]
2542+
[InlineData(4.0, 2.0, 2.0, 0.0)]
2543+
public static void LerpTest64(double value1, double value2, double amount, double expectedResult)
2544+
{
2545+
AssertExtensions.Equal(+expectedResult, NFloat.Lerp((NFloat)(+value1), (NFloat)(+value2), (NFloat)(amount)), 0);
2546+
AssertExtensions.Equal((expectedResult == 0.0) ? expectedResult : -expectedResult, NFloat.Lerp((NFloat)(-value1), (NFloat)(-value2), (NFloat)(amount)), 0);
2547+
}
24722548
}
24732549
}

src/libraries/System.Runtime/ref/System.Runtime.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,7 @@ public DivideByZeroException(string? message, System.Exception? innerException)
22042204
public static bool IsPow2(double value) { throw null; }
22052205
public static bool IsRealNumber(double value) { throw null; }
22062206
public static bool IsSubnormal(double d) { throw null; }
2207+
public static double Lerp(double value1, double value2, double amount) { throw null; }
22072208
public static double Log(double x) { throw null; }
22082209
public static double Log(double x, double newBase) { throw null; }
22092210
public static double Log10(double x) { throw null; }
@@ -2801,6 +2802,7 @@ public enum GCNotificationStatus
28012802
public static bool IsPow2(System.Half value) { throw null; }
28022803
public static bool IsRealNumber(System.Half value) { throw null; }
28032804
public static bool IsSubnormal(System.Half value) { throw null; }
2805+
public static System.Half Lerp(System.Half value1, System.Half value2, System.Half amount) { throw null; }
28042806
public static System.Half Log(System.Half x) { throw null; }
28052807
public static System.Half Log(System.Half x, System.Half newBase) { throw null; }
28062808
public static System.Half Log10(System.Half x) { throw null; }
@@ -4809,6 +4811,7 @@ public SerializableAttribute() { }
48094811
public static bool IsPow2(float value) { throw null; }
48104812
public static bool IsRealNumber(float value) { throw null; }
48114813
public static bool IsSubnormal(float f) { throw null; }
4814+
public static float Lerp(float value1, float value2, float amount) { throw null; }
48124815
public static float Log(float x) { throw null; }
48134816
public static float Log(float x, float newBase) { throw null; }
48144817
public static float Log10(float x) { throw null; }
@@ -10383,6 +10386,7 @@ public partial interface IFloatingPointIeee754<TSelf> : System.IComparable, Syst
1038310386
static abstract TSelf FusedMultiplyAdd(TSelf left, TSelf right, TSelf addend);
1038410387
static abstract TSelf Ieee754Remainder(TSelf left, TSelf right);
1038510388
static abstract int ILogB(TSelf x);
10389+
static virtual TSelf Lerp(TSelf value1, TSelf value2, TSelf amount) { throw null; }
1038610390
static virtual TSelf ReciprocalEstimate(TSelf x) { throw null; }
1038710391
static virtual TSelf ReciprocalSqrtEstimate(TSelf x) { throw null; }
1038810392
static abstract TSelf ScaleB(TSelf x, int n);

src/libraries/System.Runtime/tests/System/DoubleTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,5 +1617,43 @@ public static void TanPiTest(double value, double expectedResult, double allowed
16171617
AssertExtensions.Equal(-expectedResult, double.TanPi(-value), allowedVariance);
16181618
AssertExtensions.Equal(+expectedResult, double.TanPi(+value), allowedVariance);
16191619
}
1620+
1621+
[Theory]
1622+
[InlineData(double.NegativeInfinity, double.NegativeInfinity, 0.5, double.NegativeInfinity)]
1623+
[InlineData(double.NegativeInfinity, double.NaN, 0.5, double.NaN)]
1624+
[InlineData(double.NegativeInfinity, double.PositiveInfinity, 0.5, double.NaN)]
1625+
[InlineData(double.NegativeInfinity, 0.0, 0.5, double.NegativeInfinity)]
1626+
[InlineData(double.NegativeInfinity, 1.0, 0.5, double.NegativeInfinity)]
1627+
[InlineData(double.NaN, double.NegativeInfinity, 0.5, double.NaN)]
1628+
[InlineData(double.NaN, double.NaN, 0.5, double.NaN)]
1629+
[InlineData(double.NaN, double.PositiveInfinity, 0.5, double.NaN)]
1630+
[InlineData(double.NaN, 0.0, 0.5, double.NaN)]
1631+
[InlineData(double.NaN, 1.0, 0.5, double.NaN)]
1632+
[InlineData(double.PositiveInfinity, double.NegativeInfinity, 0.5, double.NaN)]
1633+
[InlineData(double.PositiveInfinity, double.NaN, 0.5, double.NaN)]
1634+
[InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.5, double.PositiveInfinity)]
1635+
[InlineData(double.PositiveInfinity, 0.0, 0.5, double.PositiveInfinity)]
1636+
[InlineData(double.PositiveInfinity, 1.0, 0.5, double.PositiveInfinity)]
1637+
[InlineData(1.0, 3.0, 0.0, 1.0)]
1638+
[InlineData(1.0, 3.0, 0.5, 2.0)]
1639+
[InlineData(1.0, 3.0, 1.0, 3.0)]
1640+
[InlineData(1.0, 3.0, 2.0, 5.0)]
1641+
[InlineData(2.0, 4.0, 0.0, 2.0)]
1642+
[InlineData(2.0, 4.0, 0.5, 3.0)]
1643+
[InlineData(2.0, 4.0, 1.0, 4.0)]
1644+
[InlineData(2.0, 4.0, 2.0, 6.0)]
1645+
[InlineData(3.0, 1.0, 0.0, 3.0)]
1646+
[InlineData(3.0, 1.0, 0.5, 2.0)]
1647+
[InlineData(3.0, 1.0, 1.0, 1.0)]
1648+
[InlineData(3.0, 1.0, 2.0, -1.0)]
1649+
[InlineData(4.0, 2.0, 0.0, 4.0)]
1650+
[InlineData(4.0, 2.0, 0.5, 3.0)]
1651+
[InlineData(4.0, 2.0, 1.0, 2.0)]
1652+
[InlineData(4.0, 2.0, 2.0, 0.0)]
1653+
public static void LerpTest(double value1, double value2, double amount, double expectedResult)
1654+
{
1655+
AssertExtensions.Equal(+expectedResult, double.Lerp(+value1, +value2, amount), 0);
1656+
AssertExtensions.Equal((expectedResult == 0.0) ? expectedResult : -expectedResult, double.Lerp(-value1, -value2, amount), 0);
1657+
}
16201658
}
16211659
}

0 commit comments

Comments
 (0)