Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Versioning;

namespace System
Expand Down Expand Up @@ -113,6 +114,52 @@ public static long BigMul(int a, int b)
return ((long)a) * b;
}

[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe ulong BigMul(ulong a, ulong b, out ulong low)
{
if (Bmi2.X64.IsSupported)
{
ulong tmp;
ulong high = Bmi2.X64.MultiplyNoFlags(a, b, &tmp);
low = tmp;
return high;
}

return SoftwareFallback(a, b, out low);

static ulong SoftwareFallback(ulong a, ulong b, out ulong low)
{
// It's adoption of algorithm for multiplication
// of 32-bit unsigned integers described
// in Hacker's Delight by Henry S. Warren, Jr. (ISBN 0-201-91465-4), Chapter 8
// Basically, it's an optimized version of FOIL method applied to
// low and high dwords of each operand
const ulong lowBitsMask = 0xFFFFFFFFU;

ulong al = a & lowBitsMask;
ulong ah = a >> 32;
ulong bl = b & lowBitsMask;
ulong bh = b >> 32;

ulong mull = al * bl;
ulong t = ah * bl + (mull >> 32);
ulong tl = t & lowBitsMask;

tl += al * bh;
low = tl << 32 | mull & lowBitsMask;

return ah * bh + (t >> 32) + (tl >> 32);
}
}

public static long BigMul(long a, long b, out long low)
{
ulong high = BigMul((ulong)a, (ulong)b, out ulong ulow);
low = (long)ulow;
return (long)high - ((a >> 63) & b) - ((b >> 63) & a);
}

public static double BitDecrement(double x)
{
long bits = BitConverter.DoubleToInt64Bits(x);
Expand Down
30 changes: 30 additions & 0 deletions src/libraries/System.Runtime.Extensions/tests/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,36 @@ public static void BigMul()
Assert.Equal(0L, Math.BigMul(0, 0));
}

[Theory]
[InlineData(0U, 0U, "00000000000000000000000000000000")]
[InlineData(0U, 1U, "00000000000000000000000000000000")]
[InlineData(1U, 0U, "00000000000000000000000000000000")]
[InlineData(2U, 3U, "00000000000000000000000000000006")]
[InlineData(ulong.MaxValue, 2, "0000000000000001FFFFFFFFFFFFFFFE")]
[InlineData(ulong.MaxValue, 1, "0000000000000000FFFFFFFFFFFFFFFF")]
[InlineData(ulong.MaxValue, ulong.MaxValue, "FFFFFFFFFFFFFFFE0000000000000001")]
[InlineData(ulong.MaxValue, 3, "0000000000000002FFFFFFFFFFFFFFFD")]
public static void BigMul128_Unsigned(ulong a, ulong b, string result)
{
ulong high = Math.BigMul(a, b, out ulong low);
Assert.Equal(result, high.ToString("X16") + low.ToString("X16"));
}

[Theory]
[InlineData(0L, 0L, "00000000000000000000000000000000")]
[InlineData(0L, 1L, "00000000000000000000000000000000")]
[InlineData(1L, 0L, "00000000000000000000000000000000")]
[InlineData(2L, 3L, "00000000000000000000000000000006")]
[InlineData(3L, -2L, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA")]
[InlineData(-1L, -1L, "00000000000000000000000000000001")]
[InlineData(-1L, long.MinValue, "00000000000000008000000000000000")]
[InlineData(1L, long.MinValue, "FFFFFFFFFFFFFFFF8000000000000000")]
public static void BigMul128_Signed(long a, long b, string result)
{
long high = Math.BigMul(a, b, out long low);
Assert.Equal(result, high.ToString("X16") + low.ToString("X16"));
}

[Theory]
[InlineData(1073741, 2147483647, 2000, 1647)]
[InlineData(6, 13952, 2000, 1952)]
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2548,6 +2548,9 @@ public static partial class Math
public static double Atan2(double y, double x) { throw null; }
public static double Atanh(double d) { throw null; }
public static long BigMul(int a, int b) { throw null; }
[System.CLSCompliantAttribute(false)]
public static ulong BigMul(ulong a, ulong b, out ulong low) { throw null; }
public static long BigMul(long a, long b, out long low) { throw null; }
public static double BitDecrement(double x) { throw null; }
public static double BitIncrement(double x) { throw null; }
public static double Cbrt(double d) { throw null; }
Expand Down