Skip to content

Commit

Permalink
Adding some new functions to System.Math and System.MathF (dotnet#20788)
Browse files Browse the repository at this point in the history
* Adding BitIncrement, BitDecrement, CopySign, MaxMagnitude, and MinMagnitude to Math and MathF

* Adding FusedMultiplyAdd, IlogB, Log2, and ScaleB to Math and MathF

* Adding some basic PAL tests for fma, ilogb, log2, and scalbn

* Fixing a couple typos and adding clarifying comments

* Fixing the MSVC _VVV FCALL declarations
  • Loading branch information
tannergooding authored and A-And committed Nov 20, 2018
1 parent 4930442 commit 3137cea
Show file tree
Hide file tree
Showing 47 changed files with 1,814 additions and 50 deletions.
99 changes: 81 additions & 18 deletions src/System.Private.CoreLib/shared/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,76 @@ public static long BigMul(int a, int b)
return ((long)a) * b;
}

public static double BitDecrement(double x)
{
var bits = BitConverter.DoubleToInt64Bits(x);

if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000)
{
// NaN returns NaN
// -Infinity returns -Infinity
// +Infinity returns double.MaxValue
return (bits == 0x7FF00000_00000000) ? double.MaxValue : x;
}

if (bits == 0x00000000_00000000)
{
// +0.0 returns -double.Epsilon
return -double.Epsilon;
}

// Negative values need to be incremented
// Positive values need to be decremented

bits += ((bits < 0) ? +1 : -1);
return BitConverter.Int64BitsToDouble(bits);
}

public static double BitIncrement(double x)
{
var bits = BitConverter.DoubleToInt64Bits(x);

if (((bits >> 32) & 0x7FF00000) >= 0x7FF00000)
{
// NaN returns NaN
// -Infinity returns double.MinValue
// +Infinity returns +Infinity
return (bits == unchecked((long)(0xFFF00000_00000000))) ? double.MinValue : x;
}

if (bits == unchecked((long)(0x80000000_00000000)))
{
// -0.0 returns double.Epsilon
return double.Epsilon;
}

// Negative values need to be decremented
// Positive values need to be incremented

bits += ((bits < 0) ? -1 : +1);
return BitConverter.Int64BitsToDouble(bits);
}

public static unsafe double CopySign(double x, double y)
{
// This method is required to work for all inputs,
// including NaN, so we operate on the raw bits.

var xbits = BitConverter.DoubleToInt64Bits(x);
var ybits = BitConverter.DoubleToInt64Bits(y);

// If the sign bits of x and y are not the same,
// flip the sign bit of x and return the new value;
// otherwise, just return x

if ((xbits ^ ybits) < 0)
{
return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue);
}

return x;
}

public static int DivRem(int a, int b, out int result)
{
// TODO https://github.com/dotnet/coreclr/issues/3439:
Expand Down Expand Up @@ -542,6 +612,11 @@ public static ulong Max(ulong val1, ulong val2)
return (val1 >= val2) ? val1 : val2;
}

public static double MaxMagnitude(double x, double y)
{
return Max(Abs(x), Abs(y));
}

[NonVersionable]
public static byte Min(byte val1, byte val2)
{
Expand Down Expand Up @@ -630,6 +705,11 @@ public static ulong Min(ulong val1, ulong val2)
return (val1 <= val2) ? val1 : val2;
}

public static double MinMagnitude(double x, double y)
{
return Min(Abs(x), Abs(y));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static decimal Round(decimal d)
{
Expand Down Expand Up @@ -680,7 +760,7 @@ public static double Round(double a)
flrTempVal -= 1.0;
}

return copysign(flrTempVal, a);
return CopySign(flrTempVal, a);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down Expand Up @@ -810,23 +890,6 @@ public static unsafe double Truncate(double d)
return d;
}

private static unsafe double copysign(double x, double y)
{
var xbits = BitConverter.DoubleToInt64Bits(x);
var ybits = BitConverter.DoubleToInt64Bits(y);

// If the sign bits of x and y are not the same,
// flip the sign bit of x and return the new value;
// otherwise, just return x

if (((xbits ^ ybits) >> 63) != 0)
{
return BitConverter.Int64BitsToDouble(xbits ^ long.MinValue);
}

return x;
}

private static void ThrowMinMaxException<T>(T min, T max)
{
throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max));
Expand Down
97 changes: 80 additions & 17 deletions src/System.Private.CoreLib/shared/System/MathF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,76 @@ public static float Abs(float x)
return Math.Abs(x);
}

public static float BitDecrement(float x)
{
var bits = BitConverter.SingleToInt32Bits(x);

if ((bits & 0x7F800000) >= 0x7F800000)
{
// NaN returns NaN
// -Infinity returns -Infinity
// +Infinity returns float.MaxValue
return (bits == 0x7F800000) ? float.MaxValue : x;
}

if (bits == 0x00000000)
{
// +0.0 returns -float.Epsilon
return -float.Epsilon;
}

// Negative values need to be incremented
// Positive values need to be decremented

bits += ((bits < 0) ? +1 : -1);
return BitConverter.Int32BitsToSingle(bits);
}

public static float BitIncrement(float x)
{
var bits = BitConverter.SingleToInt32Bits(x);

if ((bits & 0x7F800000) >= 0x7F800000)
{
// NaN returns NaN
// -Infinity returns float.MinValue
// +Infinity returns +Infinity
return (bits == unchecked((int)(0xFF800000))) ? float.MinValue : x;
}

if (bits == unchecked((int)(0x80000000)))
{
// -0.0 returns float.Epsilon
return float.Epsilon;
}

// Negative values need to be decremented
// Positive values need to be incremented

bits += ((bits < 0) ? -1 : +1);
return BitConverter.Int32BitsToSingle(bits);
}

public static unsafe float CopySign(float x, float y)
{
// This method is required to work for all inputs,
// including NaN, so we operate on the raw bits.

var xbits = BitConverter.SingleToInt32Bits(x);
var ybits = BitConverter.SingleToInt32Bits(y);

// If the sign bits of x and y are not the same,
// flip the sign bit of x and return the new value;
// otherwise, just return x

if ((xbits ^ ybits) < 0)
{
return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue);
}

return x;
}

public static float IEEERemainder(float x, float y)
{
if (float.IsNaN(x))
Expand Down Expand Up @@ -118,12 +188,22 @@ public static float Max(float x, float y)
return Math.Max(x, y);
}

public static float MaxMagnitude(float x, float y)
{
return Max(Abs(x), Abs(y));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Min(float x, float y)
{
return Math.Min(x, y);
}

public static float MinMagnitude(float x, float y)
{
return Min(Abs(x), Abs(y));
}

[Intrinsic]
public static float Round(float x)
{
Expand Down Expand Up @@ -214,22 +294,5 @@ public static unsafe float Truncate(float x)
ModF(x, &x);
return x;
}

private static unsafe float CopySign(float x, float y)
{
var xbits = BitConverter.SingleToInt32Bits(x);
var ybits = BitConverter.SingleToInt32Bits(y);

// If the sign bits of x and y are not the same,
// flip the sign bit of x and return the new value;
// otherwise, just return x

if (((xbits ^ ybits) >> 31) != 0)
{
return BitConverter.Int32BitsToSingle(xbits ^ int.MinValue);
}

return x;
}
}
}
12 changes: 12 additions & 0 deletions src/System.Private.CoreLib/src/System/Math.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,27 @@ public static partial class Math
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Floor(double d);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double FusedMultiplyAdd(double x, double y, double z);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int IlogB(double x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Log(double d);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Log2(double x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Log10(double d);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Pow(double x, double y);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double ScaleB(double x, int n);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double Sin(double a);

Expand Down
12 changes: 12 additions & 0 deletions src/System.Private.CoreLib/src/System/MathF.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,27 @@ public static partial class MathF
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Floor(float x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float FusedMultiplyAdd(float x, float y, float z);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int IlogB(float x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Log(float x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Log2(float x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Log10(float x);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Pow(float x, float y);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float ScaleB(float x, int n);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern float Sin(float x);

Expand Down
36 changes: 36 additions & 0 deletions src/classlibnative/float/floatdouble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,24 @@ FCIMPL2_VV(double, COMDouble::FMod, double x, double y)
return (double)fmod(x, y);
FCIMPLEND

/*=====================================FusedMultiplyAdd==========================
**
==============================================================================*/
FCIMPL3_VVV(double, COMDouble::FusedMultiplyAdd, double x, double y, double z)
FCALL_CONTRACT;

return (double)fma(x, y, z);
FCIMPLEND

/*=====================================Ilog2====================================
**
==============================================================================*/
FCIMPL1_V(int, COMDouble::IlogB, double x)
FCALL_CONTRACT;

return (int)ilogb(x);
FCIMPLEND

/*=====================================Log======================================
**
==============================================================================*/
Expand All @@ -209,6 +227,15 @@ FCIMPL1_V(double, COMDouble::Log, double x)
return (double)log(x);
FCIMPLEND

/*=====================================Log2=====================================
**
==============================================================================*/
FCIMPL1_V(double, COMDouble::Log2, double x)
FCALL_CONTRACT;

return (double)log2(x);
FCIMPLEND

/*====================================Log10=====================================
**
==============================================================================*/
Expand Down Expand Up @@ -236,6 +263,15 @@ FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
return (double)pow(x, y);
FCIMPLEND

/*=====================================ScaleB===================================
**
==============================================================================*/
FCIMPL2_VI(double, COMDouble::ScaleB, double x, int n)
FCALL_CONTRACT;

return (double)scalbn(x, n);
FCIMPLEND

/*=====================================Sin======================================
**
==============================================================================*/
Expand Down
Loading

0 comments on commit 3137cea

Please sign in to comment.