diff options
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs | 29 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Decimal.cs | 10 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Math.cs | 52 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/MathF.cs | 54 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/MidpointRounding.cs | 3 | ||||
-rw-r--r-- | tests/CoreFX/CoreFX.issues.json | 4 |
6 files changed, 106 insertions, 46 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs b/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs index 774c5d9a52..51f588e1f5 100644 --- a/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs +++ b/src/System.Private.CoreLib/shared/System/Decimal.DecCalc.cs @@ -1243,7 +1243,7 @@ ReturnResult: else { if (scale != 0) - InternalRound(ref pdecIn, (uint)scale, RoundingMode.ToEven); + InternalRound(ref pdecIn, (uint)scale, MidpointRounding.ToEven); if (pdecIn.High != 0) goto ThrowOverflow; value = (long)pdecIn.Low64; @@ -2408,19 +2408,8 @@ ThrowOverflow: } } - internal enum RoundingMode - { - ToEven = 0, - AwayFromZero = 1, - Truncate = 2, - Floor = 3, - Ceiling = 4, - } - - /// <summary> - /// Does an in-place round by the specified scale - /// </summary> - internal static void InternalRound(ref DecCalc d, uint scale, RoundingMode mode) + // Does an in-place round by the specified scale + internal static void InternalRound(ref DecCalc d, uint scale, MidpointRounding mode) { // the scale becomes the desired decimal count d.uflags -= scale << ScaleShift; @@ -2473,7 +2462,7 @@ ThrowOverflow: ulong tmp = d.Low64; if (tmp == 0) { - if (mode <= RoundingMode.Truncate) + if (mode <= MidpointRounding.ToZero) goto done; remainder = 0; goto checkRemainder; @@ -2503,9 +2492,9 @@ ThrowOverflow: } checkRemainder: - if (mode == RoundingMode.Truncate) + if (mode == MidpointRounding.ToZero) goto done; - else if (mode == RoundingMode.ToEven) + else if (mode == MidpointRounding.ToEven) { // To do IEEE rounding, we add LSB of result to sticky bits so either causes round up if remainder * 2 == last divisor. remainder <<= 1; @@ -2514,14 +2503,14 @@ checkRemainder: if (power >= remainder) goto done; } - else if (mode == RoundingMode.AwayFromZero) + else if (mode == MidpointRounding.AwayFromZero) { // Round away from zero at the mid point. remainder <<= 1; if (power > remainder) goto done; } - else if (mode == RoundingMode.Floor) + else if (mode == MidpointRounding.ToNegativeInfinity) { // Round toward -infinity if we have chopped off a non-zero amount from a negative value. if ((remainder | sticky) == 0 || !d.IsNegative) @@ -2529,7 +2518,7 @@ checkRemainder: } else { - Debug.Assert(mode == RoundingMode.Ceiling); + Debug.Assert(mode == MidpointRounding.ToPositiveInfinity); // Round toward infinity if we have chopped off a non-zero amount from a positive value. if ((remainder | sticky) == 0 || d.IsNegative) goto done; diff --git a/src/System.Private.CoreLib/shared/System/Decimal.cs b/src/System.Private.CoreLib/shared/System/Decimal.cs index c4a76d79bc..cfcb12d5d7 100644 --- a/src/System.Private.CoreLib/shared/System/Decimal.cs +++ b/src/System.Private.CoreLib/shared/System/Decimal.cs @@ -327,7 +327,7 @@ namespace System { int flags = d.flags; if ((flags & ScaleMask) != 0) - DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Ceiling); + DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToPositiveInfinity); return d; } @@ -407,7 +407,7 @@ namespace System { int flags = d.flags; if ((flags & ScaleMask) != 0) - DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Floor); + DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToNegativeInfinity); return d; } @@ -617,12 +617,12 @@ namespace System { if ((uint)decimals > 28) throw new ArgumentOutOfRangeException(nameof(decimals), SR.ArgumentOutOfRange_DecimalRound); - if ((uint)mode > (uint)MidpointRounding.AwayFromZero) + if ((uint)mode > (uint)MidpointRounding.ToPositiveInfinity) throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); int scale = d.Scale - decimals; if (scale > 0) - DecCalc.InternalRound(ref AsMutable(ref d), (uint)scale, (DecCalc.RoundingMode)mode); + DecCalc.InternalRound(ref AsMutable(ref d), (uint)scale, mode); return d; } @@ -829,7 +829,7 @@ namespace System { int flags = d.flags; if ((flags & ScaleMask) != 0) - DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), DecCalc.RoundingMode.Truncate); + DecCalc.InternalRound(ref AsMutable(ref d), (byte)(flags >> ScaleShift), MidpointRounding.ToZero); } public static implicit operator decimal(byte value) diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs index af74185a88..1c36c9d230 100644 --- a/src/System.Private.CoreLib/shared/System/Math.cs +++ b/src/System.Private.CoreLib/shared/System/Math.cs @@ -892,7 +892,7 @@ namespace System throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits); } - if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) + if (mode < MidpointRounding.ToEven || mode > MidpointRounding.ToPositiveInfinity) { throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); } @@ -903,20 +903,52 @@ namespace System value *= power10; - if (mode == MidpointRounding.AwayFromZero) + switch (mode) { - var fraction = ModF(value, &value); + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value with an even least significant digit + case MidpointRounding.ToEven: + { + value = Round(value); + break; + } + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) + case MidpointRounding.AwayFromZero: + { + double fraction = ModF(value, &value); + + if (Abs(fraction) >= 0.5) + { + value += Sign(fraction); + } - if (Abs(fraction) >= 0.5) + break; + } + // Directed rounding: Round to the nearest value, toward to zero + case MidpointRounding.ToZero: { - value += Sign(fraction); + value = Truncate(value); + break; + } + // Directed Rounding: Round down to the next value, toward negative infinity + case MidpointRounding.ToNegativeInfinity: + { + value = Floor(value); + break; + } + // Directed rounding: Round up to the next value, toward positive infinity + case MidpointRounding.ToPositiveInfinity: + { + value = Ceiling(value); + break; + } + default: + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); } } - else - { - value = Round(value); - } - + value /= power10; } diff --git a/src/System.Private.CoreLib/shared/System/MathF.cs b/src/System.Private.CoreLib/shared/System/MathF.cs index 3bff55daeb..1defa4e40b 100644 --- a/src/System.Private.CoreLib/shared/System/MathF.cs +++ b/src/System.Private.CoreLib/shared/System/MathF.cs @@ -306,9 +306,9 @@ namespace System throw new ArgumentOutOfRangeException(nameof(digits), SR.ArgumentOutOfRange_RoundingDigits); } - if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) + if (mode < MidpointRounding.ToEven || mode > MidpointRounding.ToPositiveInfinity) { - throw new ArgumentException(SR.Format(SR.Argument_InvalidEnum, mode, nameof(MidpointRounding)), nameof(mode)); + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); } if (Abs(x) < singleRoundLimit) @@ -317,20 +317,52 @@ namespace System x *= power10; - if (mode == MidpointRounding.AwayFromZero) + switch (mode) { - var fraction = ModF(x, &x); + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value with an even least significant digit + case MidpointRounding.ToEven: + { + x = Round(x); + break; + } + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) + case MidpointRounding.AwayFromZero: + { + float fraction = ModF(x, &x); + + if (Abs(fraction) >= 0.5) + { + x += Sign(fraction); + } - if (Abs(fraction) >= 0.5f) + break; + } + // Directed rounding: Round to the nearest value, toward to zero + case MidpointRounding.ToZero: { - x += Sign(fraction); + x = Truncate(x); + break; + } + // Directed Rounding: Round down to the next value, toward negative infinity + case MidpointRounding.ToNegativeInfinity: + { + x = Floor(x); + break; + } + // Directed rounding: Round up to the next value, toward positive infinity + case MidpointRounding.ToPositiveInfinity: + { + x = Ceiling(x); + break; + } + default: + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); } } - else - { - x = Round(x); - } - + x /= power10; } diff --git a/src/System.Private.CoreLib/shared/System/MidpointRounding.cs b/src/System.Private.CoreLib/shared/System/MidpointRounding.cs index a75de43e65..835dafe7ee 100644 --- a/src/System.Private.CoreLib/shared/System/MidpointRounding.cs +++ b/src/System.Private.CoreLib/shared/System/MidpointRounding.cs @@ -8,5 +8,8 @@ namespace System { ToEven = 0, AwayFromZero = 1, + ToZero = 2, + ToNegativeInfinity = 3, + ToPositiveInfinity = 4 } } diff --git a/tests/CoreFX/CoreFX.issues.json b/tests/CoreFX/CoreFX.issues.json index d35caed1cf..610c35ed4c 100644 --- a/tests/CoreFX/CoreFX.issues.json +++ b/tests/CoreFX/CoreFX.issues.json @@ -1051,6 +1051,10 @@ "reason": "https://github.com/dotnet/coreclr/issues/12605" }, { + "name": "System.Tests.DecimalTests.Round_InvalidMidpointRounding_ThrowsArgumentException", + "reason": "outdated" + }, + { "name": "System.Tests.ArrayTests.Copy", "reason": "Needs updates for XUnit 2.4" }, |