From a184818adf1e48412152dfb9e1602bc94098168f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 24 Jan 2019 13:58:28 -0800 Subject: [PATCH] Fixing some issues with the decimal parser/formatter (dotnet/coreclr#22070) * Fixing the decimal formatting so that -0 prints as 0 * Fixing the decimal parser to consider digits still in the buffer as part of the zero/non-zero tail check Signed-off-by: dotnet-bot --- .../shared/System/Number.Formatting.cs | 19 ++++++++++++--- .../shared/System/Number.Parsing.cs | 27 +++++++++++++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/netcore/System.Private.CoreLib/shared/System/Number.Formatting.cs b/netcore/System.Private.CoreLib/shared/System/Number.Formatting.cs index 7392928959d..26045d5cd43 100644 --- a/netcore/System.Private.CoreLib/shared/System/Number.Formatting.cs +++ b/netcore/System.Private.CoreLib/shared/System/Number.Formatting.cs @@ -1576,6 +1576,13 @@ namespace System if ((number.Kind == NumberBufferKind.Decimal) && (nMaxDigits == -1)) { noRounding = true; // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant + + if (number.Digits[0] == 0) + { + // -0 should be formatted as 0 for decimal. This is normally handled by RoundNumber (which we are skipping) + goto SkipSign; + } + goto SkipRounding; } else @@ -1591,6 +1598,7 @@ namespace System if (number.IsNegative) sb.Append(info.NegativeSign); + SkipSign: FormatGeneral(ref sb, ref number, nMaxDigits, info, (char)(format - ('G' - 'E')), noRounding); break; @@ -1742,6 +1750,11 @@ namespace System } else { + if (number.Kind != NumberBufferKind.FloatingPoint) + { + // The integer types don't have a concept of -0 and decimal always format -0 as 0 + number.IsNegative = false; + } number.Scale = 0; // Decimals with scale ('0.00') should be rounded. } @@ -2269,12 +2282,12 @@ namespace System } if (i == 0) { - number.Scale = 0; - - if (number.Kind == NumberBufferKind.Integer) + if (number.Kind != NumberBufferKind.FloatingPoint) { + // The integer types don't have a concept of -0 and decimal always format -0 as 0 number.IsNegative = false; } + number.Scale = 0; // Decimals with scale ('0.00') should be rounded. } dig[i] = (byte)('\0'); diff --git a/netcore/System.Private.CoreLib/shared/System/Number.Parsing.cs b/netcore/System.Private.CoreLib/shared/System/Number.Parsing.cs index 0d3c4028b3f..5a581711d40 100644 --- a/netcore/System.Private.CoreLib/shared/System/Number.Parsing.cs +++ b/netcore/System.Private.CoreLib/shared/System/Number.Parsing.cs @@ -1623,14 +1623,29 @@ namespace System { c = *++p; - // At this point we should either be at the end of the buffer, or just - // have a single rounding digit left, and the next should be the end - Debug.Assert((c == 0) || (p[1] == 0)); + bool hasZeroTail = !number.HasNonZeroTail; - if (((c == 0) || c == '0') && !number.HasNonZeroTail) + // We might still have some additional digits, in which case they need + // to be considered as part of hasZeroTail. Some examples of this are: + // * 3.0500000000000000000001e-27 + // * 3.05000000000000000000001e-27 + // In these cases, we will have processed 3 and 0, and ended on 5. The + // buffer, however, will still contain a number of trailing zeros and + // a trailing non-zero number. + + while ((c != 0) && hasZeroTail) + { + hasZeroTail &= (c == '0'); + c = *++p; + } + + // We should either be at the end of the stream or have a non-zero tail + Debug.Assert((c == 0) || !hasZeroTail); + + if (hasZeroTail) { - // When the next digit is 5, the number is even, and all following digits are zero - // we don't need to round. + // When the next digit is 5, the number is even, and all following + // digits are zero we don't need to round. goto NoRounding; } } -- 2.11.4.GIT