diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs index 1aeb2ff7e6d083..46f08474053415 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.cs @@ -182,7 +182,8 @@ internal int Format(Span destination) if (precision >= 10) { - uint div = Math.DivRem(precision, 10, out precision); + uint div; + (div, precision) = Math.DivRem(precision, 10); destination[1] = (char)('0' + div % 10); count = 2; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs index c82a2c3c950fca..1ed63ae31a7b52 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs @@ -129,7 +129,8 @@ private static bool TryFormatStandard(TimeSpan value, StandardFormat format, str } } - totalSecondsRemaining = Math.DivRem((ulong)ticks, TimeSpan.TicksPerSecond, out ulong fraction64); + ulong fraction64; + (totalSecondsRemaining, fraction64) = Math.DivRem((ulong)ticks, TimeSpan.TicksPerSecond); fraction = (uint)fraction64; } @@ -170,7 +171,7 @@ private static bool TryFormatStandard(TimeSpan value, StandardFormat format, str if (totalSecondsRemaining > 0) { // Only compute minutes if the TimeSpan has an absolute value of >= 1 minute. - totalMinutesRemaining = Math.DivRem(totalSecondsRemaining, 60 /* seconds per minute */, out seconds); + (totalMinutesRemaining, seconds) = Math.DivRem(totalSecondsRemaining, 60 /* seconds per minute */); Debug.Assert(seconds < 60); } @@ -178,7 +179,7 @@ private static bool TryFormatStandard(TimeSpan value, StandardFormat format, str if (totalMinutesRemaining > 0) { // Only compute hours if the TimeSpan has an absolute value of >= 1 hour. - totalHoursRemaining = Math.DivRem(totalMinutesRemaining, 60 /* minutes per hour */, out minutes); + (totalHoursRemaining, minutes) = Math.DivRem(totalMinutesRemaining, 60 /* minutes per hour */); Debug.Assert(minutes < 60); } @@ -189,7 +190,7 @@ private static bool TryFormatStandard(TimeSpan value, StandardFormat format, str if (totalHoursRemaining > 0) { // Only compute days if the TimeSpan has an absolute value of >= 1 day. - days = Math.DivRem((uint)totalHoursRemaining, 24 /* hours per day */, out hours); + (days, hours) = Math.DivRem((uint)totalHoursRemaining, 24 /* hours per day */); Debug.Assert(hours < 24); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index f1c058281739ae..335a3cc2c14a51 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -271,18 +271,129 @@ public static long DivRem(long a, long b, out long result) return div; } - internal static uint DivRem(uint a, uint b, out uint result) + /// Produces the quotient and the remainder of two signed 8-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { - uint div = a / b; - result = a - (div * b); - return div; + sbyte quotient = (sbyte)(left / right); + return (quotient, (sbyte)(left - (quotient * right))); + } + + /// Produces the quotient and the remainder of two unsigned 8-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) + { + byte quotient = (byte)(left / right); + return (quotient, (byte)(left - (quotient * right))); } - internal static ulong DivRem(ulong a, ulong b, out ulong result) + /// Produces the quotient and the remainder of two signed 16-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (short Quotient, short Remainder) DivRem(short left, short right) { - ulong div = a / b; - result = a - (div * b); - return div; + short quotient = (short)(left / right); + return (quotient, (short)(left - (quotient * right))); + } + + /// Produces the quotient and the remainder of two unsigned 16-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) + { + ushort quotient = (ushort)(left / right); + return (quotient, (ushort)(left - (quotient * right))); + } + + /// Produces the quotient and the remainder of two signed 32-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (int Quotient, int Remainder) DivRem(int left, int right) + { + int quotient = left / right; + return (quotient, left - (quotient * right)); + } + + /// Produces the quotient and the remainder of two unsigned 32-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) + { + uint quotient = left / right; + return (quotient, left - (quotient * right)); + } + + /// Produces the quotient and the remainder of two signed 64-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (long Quotient, long Remainder) DivRem(long left, long right) + { + long quotient = left / right; + return (quotient, left - (quotient * right)); + } + + /// Produces the quotient and the remainder of two unsigned 64-bit numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) + { + ulong quotient = left / right; + return (quotient, left - (quotient * right)); + } + + /// Produces the quotient and the remainder of two signed native-size numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) + { + nint quotient = left / right; + return (quotient, left - (quotient * right)); + } + + /// Produces the quotient and the remainder of two unsigned native-size numbers. + /// The dividend. + /// The divisor. + /// The quotient and the remainder of the specified numbers. + [NonVersionable] + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) + { + nuint quotient = left / right; + return (quotient, left - (quotient * right)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs index 329784737d316e..51cfa45736afb3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs @@ -446,7 +446,7 @@ public static void DivRem(ref BigInteger lhs, ref BigInteger rhs, out BigInteger if ((lhsLength == 1) && (rhsLength == 1)) { - uint quotient = Math.DivRem(lhs._blocks[0], rhs._blocks[0], out uint remainder); + (uint quotient, uint remainder) = Math.DivRem(lhs._blocks[0], rhs._blocks[0]); SetUInt32(out quo, quotient); SetUInt32(out rem, remainder); return; @@ -464,7 +464,8 @@ public static void DivRem(ref BigInteger lhs, ref BigInteger rhs, out BigInteger for (int i = quoLength - 1; i >= 0; i--) { ulong value = (carry << 32) | lhs._blocks[i]; - ulong digit = Math.DivRem(value, rhsValue, out carry); + ulong digit; + (digit, carry) = Math.DivRem(value, rhsValue); if ((digit == 0) && (i == (quoLength - 1))) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index 299e394f509a87..cc05a9b8d45588 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -1334,7 +1334,8 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) { while (--digits >= 0 || value != 0) { - value = Math.DivRem(value, 10, out uint remainder); + uint remainder; + (value, remainder) = Math.DivRem(value, 10); *(--bufferEnd) = (byte)(remainder + '0'); } return bufferEnd; @@ -1344,7 +1345,8 @@ private static unsafe void UInt32ToNumber(uint value, ref NumberBuffer number) { while (--digits >= 0 || value != 0) { - value = Math.DivRem(value, 10, out uint remainder); + uint remainder; + (value, remainder) = Math.DivRem(value, 10); *(--bufferEnd) = (char)(remainder + '0'); } return bufferEnd; @@ -1367,7 +1369,8 @@ internal static unsafe string UInt32ToDecStr(uint value) char* p = buffer + bufferLength; do { - value = Math.DivRem(value, 10, out uint remainder); + uint remainder; + (value, remainder) = Math.DivRem(value, 10); *(--p) = (char)(remainder + '0'); } while (value != 0); @@ -1409,7 +1412,8 @@ private static unsafe bool TryUInt32ToDecStr(uint value, int digits, Span { do { - value = Math.DivRem(value, 10, out uint remainder); + uint remainder; + (value, remainder) = Math.DivRem(value, 10); *(--p) = (char)(remainder + '0'); } while (value != 0); diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index 474f7074a217a7..b1217121ef6b54 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -624,7 +624,8 @@ private static bool TryDigitGenCounted(in DiyFp w, int requestedDigits, Span 0) { - uint digit = Math.DivRem(integrals, divisor, out integrals); + uint digit; + (digit, integrals) = Math.DivRem(integrals, divisor); Debug.Assert(digit <= 9); buffer[length] = (byte)('0' + digit); @@ -802,7 +803,8 @@ private static bool TryDigitGenShortest(in DiyFp low, in DiyFp w, in DiyFp high, // The divisor is the biggest power of ten that is smaller than integrals while (kappa > 0) { - uint digit = Math.DivRem(integrals, divisor, out integrals); + uint digit; + (digit, integrals) = Math.DivRem(integrals, divisor); Debug.Assert(digit <= 9); buffer[length] = (byte)('0' + digit); diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs b/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs index 788697ffb70a90..6da4045ea67a8a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs @@ -261,7 +261,7 @@ private static ulong ConvertBigIntegerToFloatingPointBits(ref BigInteger value, return AssembleFloatingPointBits(in info, value.ToUInt64(), baseExponent, !hasNonZeroFractionalPart); } - uint topBlockIndex = Math.DivRem(integerBitsOfPrecision, 32, out uint topBlockBits); + (uint topBlockIndex, uint topBlockBits) = Math.DivRem(integerBitsOfPrecision, 32); uint middleBlockIndex = topBlockIndex - 1; uint bottomBlockIndex = middleBlockIndex - 1; diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Math.cs b/src/libraries/System.Runtime.Extensions/tests/System/Math.cs index dde176dce8a6c5..a7742665672122 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/Math.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/Math.cs @@ -4,6 +4,7 @@ using Xunit; using Xunit.Sdk; using System.Collections.Generic; +using System.Runtime.CompilerServices; #pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0 @@ -1802,34 +1803,276 @@ public static void BigMul128_Signed(long a, long b, string result) } [Theory] - [InlineData(1073741, 2147483647, 2000, 1647)] - [InlineData(6, 13952, 2000, 1952)] - [InlineData(0, 0, 2000, 0)] - [InlineData(-7, -14032, 2000, -32)] - [InlineData(-1073741, -2147483648, 2000, -1648)] - [InlineData(-1073741, 2147483647, -2000, 1647)] - [InlineData(-6, 13952, -2000, 1952)] - public static void DivRem(int quotient, int dividend, int divisor, int expectedRemainder) - { - int remainder; - Assert.Equal(quotient, Math.DivRem(dividend, divisor, out remainder)); - Assert.Equal(expectedRemainder, remainder); + [InlineData(sbyte.MaxValue, sbyte.MaxValue, 1, 0)] + [InlineData(sbyte.MaxValue, 1, sbyte.MaxValue, 0)] + [InlineData(sbyte.MaxValue, 2, 63, 1)] + [InlineData(sbyte.MaxValue, -1, -127, 0)] + [InlineData(11, 22, 0, 11)] + [InlineData(80, 22, 3, 14)] + [InlineData(80, -22, -3, 14)] + [InlineData(-80, 22, -3, -14)] + [InlineData(-80, -22, 3, -14)] + [InlineData(0, 1, 0, 0)] + [InlineData(0, sbyte.MaxValue, 0, 0)] + [InlineData(sbyte.MinValue, sbyte.MaxValue, -1, -1)] + [InlineData(sbyte.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemSByte(sbyte dividend, sbyte divisor, sbyte expectedQuotient, sbyte expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + } + + [Theory] + [InlineData(byte.MaxValue, byte.MaxValue, 1, 0)] + [InlineData(byte.MaxValue, 1, byte.MaxValue, 0)] + [InlineData(byte.MaxValue, 2, 127, 1)] + [InlineData(52, 5, 10, 2)] + [InlineData(100, 33, 3, 1)] + [InlineData(0, 1, 0, 0)] + [InlineData(0, byte.MaxValue, 0, 0)] + [InlineData(250, 50, 5, 0)] + [InlineData(byte.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemByte(byte dividend, byte divisor, byte expectedQuotient, byte expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + } + + [Theory] + [InlineData(short.MaxValue, short.MaxValue, 1, 0)] + [InlineData(short.MaxValue, 1, short.MaxValue, 0)] + [InlineData(short.MaxValue, 2, 16383, 1)] + [InlineData(short.MaxValue, -1, -32767, 0)] + [InlineData(12345, 22424, 0, 12345)] + [InlineData(300, 22, 13, 14)] + [InlineData(300, -22, -13, 14)] + [InlineData(-300, 22, -13, -14)] + [InlineData(-300, -22, 13, -14)] + [InlineData(0, 1, 0, 0)] + [InlineData(0, short.MaxValue, 0, 0)] + [InlineData(short.MinValue, short.MaxValue, -1, -1)] + [InlineData(13952, 2000, 6, 1952)] + [InlineData(short.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemInt16(short dividend, short divisor, short expectedQuotient, short expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + } + + [Theory] + [InlineData(ushort.MaxValue, ushort.MaxValue, 1, 0)] + [InlineData(ushort.MaxValue, 1, ushort.MaxValue, 0)] + [InlineData(ushort.MaxValue, 2, 32767, 1)] + [InlineData(12345, 42424, 0, 12345)] + [InlineData(51474, 31474, 1, 20000)] + [InlineData(10000, 333, 30, 10)] + [InlineData(0, 1, 0, 0)] + [InlineData(0, ushort.MaxValue, 0, 0)] + [InlineData(13952, 2000, 6, 1952)] + [InlineData(ushort.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemUInt16(ushort dividend, ushort divisor, ushort expectedQuotient, ushort expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + } + + [Theory] + [InlineData(2147483647, 2000, 1073741, 1647)] + [InlineData(13952, 2000, 6, 1952)] + [InlineData(0, 2000, 0, 0)] + [InlineData(-14032, 2000, -7, -32)] + [InlineData(-2147483648, 2000, -1073741, -1648)] + [InlineData(2147483647, -2000, -1073741, 1647)] + [InlineData(13952, -2000, -6, 1952)] + [InlineData(13952, 0, 0, 0)] + [InlineData(int.MaxValue, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemInt32(int dividend, int divisor, int expectedQuotient, int expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + Assert.Throws(() => Math.DivRem(dividend, divisor, out int remainder)); + } + else + { + Assert.Equal(expectedQuotient, Math.DivRem(dividend, divisor, out int remainder)); + Assert.Equal(expectedRemainder, remainder); + + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + if (IntPtr.Size == 4) + { + DivRemNativeInt(dividend, divisor, expectedQuotient, expectedRemainder); + } + } + + [Theory] + [InlineData(uint.MaxValue, uint.MaxValue, 1, 0)] + [InlineData(uint.MaxValue, 1, uint.MaxValue, 0)] + [InlineData(uint.MaxValue, 2, 2147483647, 1)] + [InlineData(123456789, 4242424242, 0, 123456789)] + [InlineData(514748364, 3147483647, 0, 514748364)] + [InlineData(1000000, 333, 3003, 1)] + [InlineData(0, 1, 0, 0)] + [InlineData(0UL, uint.MaxValue, 0, 0)] + [InlineData(13952, 2000, 6, 1952)] + [InlineData(uint.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemUInt32(uint dividend, uint divisor, uint expectedQuotient, uint expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + if (IntPtr.Size == 4) + { + DivRemNativeUInt(dividend, divisor, expectedQuotient, expectedRemainder); + } } [Theory] - [InlineData(4611686018427387L, 9223372036854775807L, 2000L, 1807L)] - [InlineData(4611686018427387L, -9223372036854775808L, -2000L, -1808L)] - [InlineData(-4611686018427387L, 9223372036854775807L, -2000L, 1807L)] - [InlineData(-4611686018427387L, -9223372036854775808L, 2000L, -1808L)] - [InlineData(6L, 13952L, 2000L, 1952L)] - [InlineData(0L, 0L, 2000L, 0L)] - [InlineData(-7L, -14032L, 2000L, -32L)] - [InlineData(-6L, 13952L, -2000L, 1952L)] - public static void DivRemLong(long quotient, long dividend, long divisor, long expectedRemainder) + [InlineData(9223372036854775807L, 2000L, 4611686018427387L, 1807L)] + [InlineData(-9223372036854775808L, -2000L, 4611686018427387L, -1808L)] + [InlineData(9223372036854775807L, -2000L, -4611686018427387L, 1807L)] + [InlineData(-9223372036854775808L, 2000L, -4611686018427387L, -1808L)] + [InlineData(13952L, 2000L, 6L, 1952L)] + [InlineData(0L, 2000L, 0L, 0L)] + [InlineData(-14032L, 2000L, -7L, -32L)] + [InlineData(13952L, -2000L, -6L, 1952L)] + [InlineData(long.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemInt64(long dividend, long divisor, long expectedQuotient, long expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + Assert.Throws(() => Math.DivRem(dividend, divisor, out long remainder)); + } + else + { + Assert.Equal(expectedQuotient, Math.DivRem(dividend, divisor, out long remainder)); + Assert.Equal(expectedRemainder, remainder); + + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + if (IntPtr.Size == 8) + { + DivRemNativeInt((nint)dividend, (nint)divisor, (nint)expectedQuotient, (nint)expectedRemainder); + } + } + + [Theory] + [InlineData(ulong.MaxValue, ulong.MaxValue, 1, 0)] + [InlineData(ulong.MaxValue, 1, ulong.MaxValue, 0)] + [InlineData(ulong.MaxValue, 2, 9223372036854775807, 1)] + [InlineData(123456789, 4242424242, 0, 123456789)] + [InlineData(5147483647, 3147483647, 1, 2000000000)] + [InlineData(1000000, 333, 3003, 1)] + [InlineData(0, 1, 0, 0)] + [InlineData(0UL, ulong.MaxValue, 0, 0)] + [InlineData(13952, 2000, 6, 1952)] + [InlineData(ulong.MaxValue, 0, 0, 0)] + [InlineData(1, 0, 0, 0)] + [InlineData(0, 0, 0, 0)] + public static void DivRemUInt64(ulong dividend, ulong divisor, ulong expectedQuotient, ulong expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + if (IntPtr.Size == 8) + { + DivRemNativeUInt((nuint)dividend, (nuint)divisor, (nuint)expectedQuotient, (nuint)expectedRemainder); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void DivRemNativeInt(nint dividend, nint divisor, nint expectedQuotient, nint expectedRemainder) { - long remainder; - Assert.Equal(quotient, Math.DivRem(dividend, divisor, out remainder)); - Assert.Equal(expectedRemainder, remainder); + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void DivRemNativeUInt(nuint dividend, nuint divisor, nuint expectedQuotient, nuint expectedRemainder) + { + if (divisor == 0) + { + Assert.Throws(() => Math.DivRem(dividend, divisor)); + } + else + { + var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor); + Assert.Equal(expectedQuotient, actualQuotient); + Assert.Equal(expectedRemainder, actualRemainder); + } } public static IEnumerable Clamp_UnsignedInt_TestData() diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 55d08098348307..d92bf693dad744 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -2696,6 +2696,21 @@ public static partial class Math public static double Cosh(double value) { throw null; } public static int DivRem(int a, int b, out int result) { throw null; } public static long DivRem(long a, long b, out long result) { throw null; } + public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { throw null; } + [System.CLSCompliantAttribute(false)] + public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { throw null; } + public static (short Quotient, short Remainder) DivRem(short left, short right) { throw null; } + [System.CLSCompliantAttribute(false)] + public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { throw null; } + public static (int Quotient, int Remainder) DivRem(int left, int right) { throw null; } + [System.CLSCompliantAttribute(false)] + public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { throw null; } + public static (long Quotient, long Remainder) DivRem(long left, long right) { throw null; } + [System.CLSCompliantAttribute(false)] + public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { throw null; } + public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { throw null; } + [System.CLSCompliantAttribute(false)] + public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { throw null; } public static double Exp(double d) { throw null; } public static decimal Floor(decimal d) { throw null; } public static double Floor(double d) { throw null; }