Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tuple-based Math.DivRem overloads #45074

Merged
merged 8 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
65 changes: 65 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,71 @@ internal static ulong DivRem(ulong a, ulong b, out ulong result)
return div;
}

[CLSCompliant(false)]
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right)
{
sbyte quotient = (sbyte)(left / right);
return (quotient, (sbyte)(left - (quotient * right)));
}

public static (byte Quotient, byte Remainder) DivRem(byte left, byte right)
{
byte quotient = (byte)(left / right);
return (quotient, (byte)(left - (quotient * right)));
}

public static (short Quotient, short Remainder) DivRem(short left, short right)
{
short quotient = (short)(left / right);
return (quotient, (short)(left - (quotient * right)));
}

[CLSCompliant(false)]
public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right)
{
ushort quotient = (ushort)(left / right);
return (quotient, (ushort)(left - (quotient * right)));
}

public static (int Quotient, int Remainder) DivRem(int left, int right)
{
int quotient = left / right;
return (quotient, left - (quotient * right));
}

[CLSCompliant(false)]
public static (uint Quotient, uint Remainder) DivRem(uint left, uint right)
{
uint quotient = left / right;
return (quotient, left - (quotient * right));
}

public static (long Quotient, long Remainder) DivRem(long left, long right)
{
long quotient = left / right;
return (quotient, left - (quotient * right));
}

[CLSCompliant(false)]
public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right)
{
ulong quotient = left / right;
return (quotient, left - (quotient * right));
}

public static (nint Quotient, nint Remainder) DivRem(nint left, nint right)
{
nint quotient = left / right;
return (quotient, left - (quotient * right));
}

[CLSCompliant(false)]
public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right)
{
nuint quotient = left / right;
return (quotient, left - (quotient * right));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static decimal Ceiling(decimal d)
{
Expand Down
291 changes: 267 additions & 24 deletions src/libraries/System.Runtime.Extensions/tests/System/Math.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => Math.DivRem(dividend, divisor));
Assert.Throws<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => Math.DivRem(dividend, divisor));
Assert.Throws<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => 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<DivideByZeroException>(() => Math.DivRem(dividend, divisor));
}
else
{
var (actualQuotient, actualRemainder) = Math.DivRem(dividend, divisor);
Assert.Equal(expectedQuotient, actualQuotient);
Assert.Equal(expectedRemainder, actualRemainder);
}
}

public static IEnumerable<object[]> Clamp_UnsignedInt_TestData()
Expand Down
Loading