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
7 changes: 6 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/Int128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,12 @@ public static Int128 Log2(Int128 value)
return lower;
}

internal static Int128 BigMul(Int128 left, Int128 right, out Int128 lower)
/// <summary>Produces the full product of two unsigned native integers.</summary>
/// <param name="left">The integer to multiply with <paramref name="right" />.</param>
/// <param name="right">The integer to multiply with <paramref name="left" />.</param>
/// <param name="lower">The lower half of the full product.</param>
/// <returns>The upper half of the full product.</returns>
public static Int128 BigMul(Int128 left, Int128 right, out Int128 lower)
{
// This follows the same logic as is used in `long Math.BigMul(long, long, out long)`

Expand Down
18 changes: 18 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/IntPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,24 @@ public static nint MinValue
get => unchecked((nint)nint_t.MinValue);
}

/// <summary>Produces the full product of two unsigned native integers.</summary>
/// <param name="left">The integer to multiply with <paramref name="right" />.</param>
/// <param name="right">The integer to multiply with <paramref name="left" />.</param>
/// <param name="lower">The lower half of the full product.</param>
/// <returns>The upper half of the full product.</returns>
public static nint BigMul(nint left, nint right, out nint lower)
{
#if TARGET_64BIT
Int128 result = long.BigMul(left, right);
lower = (nint)result.Lower;
return (nint)result.Upper;
#else
long result = Math.BigMul((int)left, (int)right);
lower = (int)result;
return (int)(result >>> 32);
#endif
}

public int CompareTo(object? value)
{
if (value is nint other)
Expand Down
7 changes: 6 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/UInt128.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,12 @@ static uint SubtractDivisor(Span<uint> left, ReadOnlySpan<uint> right, ulong q)
return lower;
}

internal static UInt128 BigMul(UInt128 left, UInt128 right, out UInt128 lower)
/// <summary>Produces the full product of two unsigned native integers.</summary>
/// <param name="left">The integer to multiply with <paramref name="right" />.</param>
/// <param name="right">The integer to multiply with <paramref name="left" />.</param>
/// <param name="lower">The lower half of the full product.</param>
/// <returns>The upper half of the full product.</returns>
public static UInt128 BigMul(UInt128 left, UInt128 right, out UInt128 lower)
{
// Adaptation of algorithm for multiplication
// of 32-bit unsigned integers described
Expand Down
18 changes: 18 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,24 @@ public static nuint MinValue
get => unchecked((nuint)nuint_t.MinValue);
}

/// <summary>Produces the full product of two unsigned native integers.</summary>
/// <param name="left">The integer to multiply with <paramref name="right" />.</param>
/// <param name="right">The integer to multiply with <paramref name="left" />.</param>
/// <param name="lower">The lower half of the full product.</param>
/// <returns>The upper half of the full product.</returns>
public static nuint BigMul(nuint left, nuint right, out nuint lower)
{
#if TARGET_64BIT
UInt128 result = ulong.BigMul(left, right);
lower = (nuint)result.Lower;
return (nuint)result.Upper;
#else
ulong result = uint.BigMul((uint)left, (uint)right);
lower = (uint)result;
return (uint)(result >>> 32);
#endif
}

public int CompareTo(object? value)
{
if (value is nuint other)
Expand Down
4 changes: 4 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3574,6 +3574,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep
static int System.Numerics.INumberBase<System.Int128>.Radix { get { throw null; } }
public static System.Int128 Zero { get { throw null; } }
public static System.Int128 Abs(System.Int128 value) { throw null; }
public static System.Int128 BigMul(System.Int128 left, System.Int128 right, out System.Int128 lower) { throw null; }
public static System.Int128 Clamp(System.Int128 value, System.Int128 min, System.Int128 max) { throw null; }
public int CompareTo(System.Int128 value) { throw null; }
public int CompareTo(object? value) { throw null; }
Expand Down Expand Up @@ -4189,6 +4190,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep
static nint System.Numerics.ISignedNumber<nint>.NegativeOne { get { throw null; } }
public static nint Abs(nint value) { throw null; }
public static nint Add(nint pointer, int offset) { throw null; }
public static nint BigMul(nint left, nint right, out nint lower) { throw null; }
public static nint Clamp(nint value, nint min, nint max) { throw null; }
public int CompareTo(nint value) { throw null; }
public int CompareTo(object? value) { throw null; }
Expand Down Expand Up @@ -6823,6 +6825,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException)
static System.UInt128 System.Numerics.IMultiplicativeIdentity<System.UInt128,System.UInt128>.MultiplicativeIdentity { get { throw null; } }
static int System.Numerics.INumberBase<System.UInt128>.Radix { get { throw null; } }
public static System.UInt128 Zero { get { throw null; } }
public static System.UInt128 BigMul(System.UInt128 left, System.UInt128 right, out System.UInt128 lower) { throw null; }
public static System.UInt128 Clamp(System.UInt128 value, System.UInt128 min, System.UInt128 max) { throw null; }
public int CompareTo(object? value) { throw null; }
public int CompareTo(System.UInt128 value) { throw null; }
Expand Down Expand Up @@ -7443,6 +7446,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException)
static int System.Numerics.INumberBase<nuint>.Radix { get { throw null; } }
static nuint System.Numerics.INumberBase<nuint>.Zero { get { throw null; } }
public static nuint Add(nuint pointer, int offset) { throw null; }
public static nuint BigMul(nuint left, nuint right, out nuint lower) { throw null; }
public static nuint Clamp(nuint value, nuint min, nuint max) { throw null; }
public int CompareTo(object? value) { throw null; }
public int CompareTo(nuint value) { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,5 +562,29 @@ public static void Runtime75416()
Int128 b = (Int128.MaxValue - 10) * -100;
Assert.Equal(b, +1100);
}

public static IEnumerable<object[]> BigMul_TestData()
{
yield return new object[] { (Int128)0, (Int128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (Int128)0, (Int128)1, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (Int128)1, (Int128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (Int128)2, (Int128)3, "0000000000000000000000000000000000000000000000000000000000000006" };
yield return new object[] { (Int128)3, (Int128)(-2), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA" };
yield return new object[] { (Int128)(-1), (Int128)(-1), "0000000000000000000000000000000000000000000000000000000000000001" };
yield return new object[] { (Int128)(-1), Int128.MinValue, "0000000000000000000000000000000080000000000000000000000000000000" };
yield return new object[] { (Int128)1, Int128.MinValue, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000" };
yield return new object[] { new Int128(0x7DD8FD06E61C42C7, 0x23B8308969A5D354), new Int128(0x23B8308969A5D354, 0x7DD8FD06E61C42C7), "118F366A0AEB79CDF61A2AD689A481BFBA9B9B874C9A440EB340AA067592EE4C" };
yield return new object[] { new Int128(0x6DACB8FC835F41B5, 0xD26F1073812D6446), new Int128(0xD26F1073812D6446, 0x6DACB8FC835F41B5), "EC7A8BB31D6035AD30FC0550485D053B65FB0FB7A7D5A47F27742486E387AB7E" };
yield return new object[] { new Int128(0xE990583BA9EAB3D8, 0x13CF93153370AB0B), new Int128(0x13CF93153370AB0B, 0xE990583BA9EAB3D8), "FE43855FCCDA31540755B833730F08FFD0B8FE2FF36A55181A45864AC9B70248" };
yield return new object[] { new Int128(0xA85EB0478871B06C, 0xCC423B382BE5BB37), new Int128(0xCC423B382BE5BB37, 0xA85EB0478871B06C), "11B61855830A65CB4078E0668A2FEF9970B49ACA239DE4CFA363C1FE50E7CB34" };
}

[Theory]
[MemberData(nameof(BigMul_TestData))]
public static void BigMul(Int128 a, Int128 b, string result)
{
Int128 upper = Int128.BigMul(a, b, out Int128 lower);
Assert.Equal(result, $"{upper:X32}{lower:X32}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace System.Tests
{
public static class IntPtrTests
{
private static unsafe bool Is32Bit => sizeof(void*) == 4;
private static unsafe bool Is64Bit => sizeof(void*) == 8;

[Fact]
Expand Down Expand Up @@ -1074,5 +1075,43 @@ public static void ToString_C_EmptyPercentGroup_Success()
[MemberData(nameof(ToString_TestData))]
public static void TryFormat(nint i, string format, IFormatProvider provider, string expected) =>
NumberFormatTestHelper.TryFormatNumberTest(i, format, provider, expected);

[ConditionalTheory(nameof(Is32Bit))]
[InlineData(0, 0, "0000000000000000")]
[InlineData(0, 1, "0000000000000000")]
[InlineData(1, 0, "0000000000000000")]
[InlineData(2, 3, "0000000000000006")]
[InlineData(3, -2, "FFFFFFFFFFFFFFFA")]
[InlineData(-1, -1, "0000000000000001")]
[InlineData(-1, int.MinValue, "0000000080000000")]
[InlineData(1, int.MinValue, "FFFFFFFF80000000")]
[InlineData(0x19E3BD39, 0x69A5D354, "0AAF2DC48A6D11B4")]
[InlineData(0x7CA0BE4B, -0x7ED29BBA, "C2425AAB1C785482")]
[InlineData(-0x56154C28, 0x3370AB0B, "EEB3DEFEC9B70248")]
[InlineData(-0x778E4F94, -0x541A44C9, "2746F6B050E7CB34")]
public static void BigMul32(int a, int b, string result)
{
nint upper = nint.BigMul(a, b, out nint lower);
Assert.Equal(result, $"{upper:X8}{lower:X8}");
}

[ConditionalTheory(nameof(Is64Bit))]
[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")]
[InlineData(0x7DD8FD06E61C42C7, 0x23B8308969A5D354, "118F366A0AEB79CDB340AA067592EE4C")]
[InlineData(0x6DACB8FC835F41B5, -0x2D90EF8C7ED29BBA, "EC7A8BB31D6035AD27742486E387AB7E")]
[InlineData(-0x166FA7C456154C28, 0x13CF93153370AB0B, "FE43855FCCDA31541A45864AC9B70248")]
[InlineData(-0x57A14FB8778E4F94, -0x33BDC4C7D41A44C9, "11B61855830A65CBA363C1FE50E7CB34")]
public static void BigMul64(long a, long b, string result)
{
nint upper = nint.BigMul((nint)a, (nint)b, out nint lower);
Assert.Equal(result, $"{upper:X16}{lower:X16}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -496,5 +496,26 @@ public static void Runtime75416()
UInt128 b = (UInt128Tests_GenericMath.Int128MaxValue - 10u) * (UInt128)(Int128)(-100);
Assert.Equal(b, 1100u);
}

public static IEnumerable<object[]> BigMul_TestData()
{
yield return new object[] { (UInt128)0, (UInt128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (UInt128)0, (UInt128)1, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (UInt128)1, (UInt128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
yield return new object[] { (UInt128)2, (UInt128)3, "0000000000000000000000000000000000000000000000000000000000000006" };
yield return new object[] { UInt128.MaxValue, (UInt128)2, "00000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" };
yield return new object[] { UInt128.MaxValue, (UInt128)1, "00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" };
yield return new object[] { UInt128.MaxValue, UInt128.MaxValue, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001" };
yield return new object[] { UInt128.MaxValue, (UInt128)3, "00000000000000000000000000000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD" };
yield return new object[] { new UInt128(0xE8FAF08929B46BB5, 0x26B442D59782BA17), new UInt128(0x26B442D59782BA17, 0xE8FAF08929B46BB5), "23394CF891529663F897F2180AA9D1F6EA183EE8D7CCD26D1EB6255F4A612F43" };
}

[Theory]
[MemberData(nameof(BigMul_TestData))]
public static void BigMul(UInt128 a, UInt128 b, string result)
{
UInt128 upper = UInt128.BigMul(a, b, out UInt128 lower);
Assert.Equal(result, $"{upper:X32}{lower:X32}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace System.Tests
{
public static class UIntPtrTests
{
private static unsafe bool Is32Bit => sizeof(void*) == 4;
private static unsafe bool Is64Bit => sizeof(void*) == 8;

[Fact]
Expand Down Expand Up @@ -608,5 +609,37 @@ public static void Parse_Utf8Span_InvalidUtf8()
[MemberData(nameof(ToString_TestData))]
public static void TryFormat(nuint i, string format, IFormatProvider provider, string expected) =>
NumberFormatTestHelper.TryFormatNumberTest(i, format, provider, expected);

[ConditionalTheory(nameof(Is32Bit))]
[InlineData(0U, 0U, "0000000000000000")]
[InlineData(0U, 1U, "0000000000000000")]
[InlineData(1U, 0U, "0000000000000000")]
[InlineData(2U, 3U, "0000000000000006")]
[InlineData(uint.MaxValue, 2U, "00000001FFFFFFFE")]
[InlineData(uint.MaxValue, 1U, "00000000FFFFFFFF")]
[InlineData(uint.MaxValue, uint.MaxValue, "FFFFFFFE00000001")]
[InlineData(uint.MaxValue, 3U, "00000002FFFFFFFD")]
[InlineData(0x29B46BB5U, 0x9782BA17U, "18AEB7774A612F43")]
public static void BigMul32(uint a, uint b, string result)
{
nuint upper = nuint.BigMul(a, b, out nuint lower);
Assert.Equal(result, $"{upper:X8}{lower:X8}");
}

[ConditionalTheory(nameof(Is64Bit))]
[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")]
[InlineData(0xE8FAF08929B46BB5, 0x26B442D59782BA17, "23394CF8915296631EB6255F4A612F43")]
public static void BigMul64(ulong a, ulong b, string result)
{
nuint upper = nuint.BigMul((nuint)a, (nuint)b, out nuint lower);
Assert.Equal(result, $"{upper:X16}{lower:X16}");
}
}
}
Loading