Skip to content

Commit

Permalink
Use DivRem in Decimal.DecCalc (#97619)
Browse files Browse the repository at this point in the history
  • Loading branch information
lilinus authored Jan 30, 2024
1 parent df05ddc commit c794d03
Showing 1 changed file with 32 additions and 45 deletions.
77 changes: 32 additions & 45 deletions src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,20 @@ private static bool Div96ByConst(ref ulong high64, ref uint low, uint pow)
#else
// 32-bit RyuJIT doesn't convert 64-bit division by constant into multiplication by reciprocal. Do half-width divisions instead.
Debug.Assert(pow <= ushort.MaxValue);
uint num, mid32, low16, div;
uint num, mid32, low16, div, rem;
if (high64 <= uint.MaxValue)
{
num = (uint)high64;
mid32 = num / pow;
num = (num - mid32 * pow) << 16;
(mid32, rem) = Math.DivRem(num, pow);
num = rem << 16;

num += low >> 16;
low16 = num / pow;
num = (num - low16 * pow) << 16;
(low16, rem) = Math.DivRem(num, pow);
num = rem << 16;

num += (ushort)low;
div = num / pow;
if (num == div * pow)
(div, rem) = Math.DivRem(num, pow);
if (rem == 0)
{
high64 = mid32;
low = (low16 << 16) + div;
Expand All @@ -255,25 +255,25 @@ private static bool Div96ByConst(ref ulong high64, ref uint low, uint pow)
else
{
num = (uint)(high64 >> 32);
uint high32 = num / pow;
num = (num - high32 * pow) << 16;
(uint high32, rem) = Math.DivRem(num, pow);
num = rem << 16;

num += (uint)high64 >> 16;
mid32 = num / pow;
num = (num - mid32 * pow) << 16;
(mid32, rem) = Math.DivRem(num, pow);
num = rem << 16;

num += (ushort)high64;
div = num / pow;
num = (num - div * pow) << 16;
(div, rem) = Math.DivRem(num, pow);
num = rem << 16;
mid32 = div + (mid32 << 16);

num += low >> 16;
low16 = num / pow;
num = (num - low16 * pow) << 16;
(low16, rem) = Math.DivRem(num, pow);
num = rem << 16;

num += (ushort)low;
div = num / pow;
if (num == div * pow)
(div, rem) = Math.DivRem(num, pow);
if (rem == 0)
{
high64 = ((ulong)high32 << 32) | mid32;
low = (low16 << 16) + div;
Expand Down Expand Up @@ -322,7 +322,6 @@ private static void Unscale(ref uint low, ref ulong high64, ref int scale)
private static uint Div96By64(ref Buf12 bufNum, ulong den)
{
Debug.Assert(den > bufNum.High64);
uint quo;
ulong num;
uint num2 = bufNum.U2;
if (num2 == 0)
Expand All @@ -332,13 +331,11 @@ private static uint Div96By64(ref Buf12 bufNum, ulong den)
// Result is zero. Entire dividend is remainder.
return 0;

// TODO: https://github.com/dotnet/runtime/issues/5213
quo = (uint)(num / den);
num -= quo * den; // remainder
bufNum.Low64 = num;
return quo;
(ulong quo64, bufNum.Low64) = Math.DivRem(num, den);
return (uint)quo64;
}

uint quo;
uint denHigh32 = (uint)(den >> 32);
if (num2 >= denHigh32)
{
Expand Down Expand Up @@ -674,7 +671,7 @@ private static unsafe int ScaleResult(Buf24* bufRes, uint hiRes, int scale)
private static unsafe uint DivByConst(uint* result, uint hiRes, out uint quotient, out uint remainder, uint power)
{
uint high = result[hiRes];
remainder = high - (quotient = high / power) * power;
(quotient, remainder) = Math.DivRem(high, power);
for (uint i = hiRes - 1; (int)i >= 0; i--)
{
#if TARGET_64BIT
Expand All @@ -690,13 +687,11 @@ private static unsafe uint DivByConst(uint* result, uint hiRes, out uint quotien
#endif
// byte* is used here because Roslyn doesn't do constant propagation for pointer arithmetic
uint num = *(ushort*)((byte*)result + i * 4 + high16) + (remainder << 16);
uint div = num / power;
remainder = num - div * power;
(uint div, remainder) = Math.DivRem(num, power);
*(ushort*)((byte*)result + i * 4 + high16) = (ushort)div;

num = *(ushort*)((byte*)result + i * 4 + low16) + (remainder << 16);
div = num / power;
remainder = num - div * power;
(div, remainder) = Math.DivRem(num, power);
*(ushort*)((byte*)result + i * 4 + low16) = (ushort)div;
#endif
}
Expand Down Expand Up @@ -1332,10 +1327,7 @@ internal static unsafe void VarDecMul(ref DecCalc d1, ref DecCalc d2)
scale -= DEC_SCALE_MAX + 1;
ulong power = UInt64Powers10[scale];

// TODO: https://github.com/dotnet/runtime/issues/5213
tmp = low64 / power;
ulong remainder = low64 - tmp * power;
low64 = tmp;
(low64, ulong remainder) = Math.DivRem(low64, power);

// Round result. See if remainder >= 1/2 of divisor.
// Divisor is a power of 10, so it is always even.
Expand Down Expand Up @@ -1629,9 +1621,8 @@ internal static void VarDecFromR4(float input, out DecCalc result)

if ((mant & 0xF) == 0 && lmax >= 4)
{
const uint den = 10000;
uint div = mant / den;
if (mant == div * den)
(uint div, uint rem) = Math.DivRem(mant, 10000);
if (rem == 0)
{
mant = div;
power -= 4;
Expand All @@ -1641,9 +1632,8 @@ internal static void VarDecFromR4(float input, out DecCalc result)

if ((mant & 3) == 0 && lmax >= 2)
{
const uint den = 100;
uint div = mant / den;
if (mant == div * den)
(uint div, uint rem) = Math.DivRem(mant, 100);
if (rem == 0)
{
mant = div;
power -= 2;
Expand All @@ -1653,9 +1643,8 @@ internal static void VarDecFromR4(float input, out DecCalc result)

if ((mant & 1) == 0 && lmax >= 1)
{
const uint den = 10;
uint div = mant / den;
if (mant == div * den)
(uint div, uint rem) = Math.DivRem(mant, 10);
if (rem == 0)
{
mant = div;
power--;
Expand Down Expand Up @@ -2372,8 +2361,7 @@ internal static void InternalRound(ref DecCalc d, uint scale, MidpointRounding m
else
{
uint q;
d.uhi = q = n / divisor;
remainder = n - q * divisor;
(d.uhi, remainder) = Math.DivRem(n, divisor);
n = d.umid;
if ((n | remainder) != 0)
{
Expand Down Expand Up @@ -2414,8 +2402,7 @@ internal static void InternalRound(ref DecCalc d, uint scale, MidpointRounding m
else
{
uint q;
d.uhi = q = n / power;
remainder = n - q * power;
(d.uhi, remainder) = Math.DivRem(n, power);
n = d.umid;
if ((n | remainder) != 0)
{
Expand Down

0 comments on commit c794d03

Please sign in to comment.