From bedf29e7301e27d9c81583a5a5c1aa653765cd4c Mon Sep 17 00:00:00 2001 From: Pent Ploompuu Date: Wed, 18 Jul 2018 13:14:49 +0300 Subject: [PATCH] Optimize {Try}FormatDecimal (dotnet/coreclr#18935) Commit migrated from https://github.com/dotnet/coreclr/commit/fb37382267a5e015769a3b4ef127e5544fe642c7 --- .../src/System/Number.Formatting.cs | 89 +++++++++------------- .../src/System/Text/ValueStringBuilder.cs | 4 +- 2 files changed, 37 insertions(+), 56 deletions(-) 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 1ff6982..689f146 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -290,7 +290,7 @@ namespace System char fmt = ParseFormatSpecifier(format, out int digits); NumberBuffer number = default; - DecimalToNumber(value, ref number); + DecimalToNumber(ref value, ref number); ValueStringBuilder sb; unsafe @@ -316,7 +316,7 @@ namespace System char fmt = ParseFormatSpecifier(format, out int digits); NumberBuffer number = default; - DecimalToNumber(value, ref number); + DecimalToNumber(ref value, ref number); ValueStringBuilder sb; unsafe @@ -337,10 +337,8 @@ namespace System return sb.TryCopyTo(destination, out charsWritten); } - private static unsafe void DecimalToNumber(decimal value, ref NumberBuffer number) + private static unsafe void DecimalToNumber(ref decimal d, ref NumberBuffer number) { - decimal d = value; - char* buffer = number.digits; number.precision = DecimalPrecision; number.sign = d.IsNegative; @@ -352,7 +350,7 @@ namespace System } p = UInt32ToDecChars(p, d.Low, 0); - int i = (int)(buffer + DecimalPrecision - p); + int i = (int)((byte*)(buffer + DecimalPrecision) - (byte*)p) >> 1; number.scale = i - d.Scale; char* dst = number.digits; @@ -1465,20 +1463,17 @@ namespace System internal static unsafe void NumberToString(ref ValueStringBuilder sb, ref NumberBuffer number, char format, int nMaxDigits, NumberFormatInfo info, bool isDecimal) { - int nMinDigits = -1; - switch (format) { case 'C': case 'c': { - nMinDigits = nMaxDigits >= 0 ? nMaxDigits : info.CurrencyDecimalDigits; if (nMaxDigits < 0) nMaxDigits = info.CurrencyDecimalDigits; RoundNumber(ref number, number.scale + nMaxDigits); // Don't change this line to use digPos since digCount could have its sign changed. - FormatCurrency(ref sb, ref number, nMinDigits, nMaxDigits, info); + FormatCurrency(ref sb, ref number, nMaxDigits, info); break; } @@ -1487,16 +1482,14 @@ namespace System case 'f': { if (nMaxDigits < 0) - nMaxDigits = nMinDigits = info.NumberDecimalDigits; - else - nMinDigits = nMaxDigits; + nMaxDigits = info.NumberDecimalDigits; RoundNumber(ref number, number.scale + nMaxDigits); if (number.sign) sb.Append(info.NegativeSign); - FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, null, info.NumberDecimalSeparator, null); + FormatFixed(ref sb, ref number, nMaxDigits, info, null, info.NumberDecimalSeparator, null); break; } @@ -1505,13 +1498,11 @@ namespace System case 'n': { if (nMaxDigits < 0) - nMaxDigits = nMinDigits = info.NumberDecimalDigits; // Since we are using digits in our calculation - else - nMinDigits = nMaxDigits; + nMaxDigits = info.NumberDecimalDigits; // Since we are using digits in our calculation RoundNumber(ref number, number.scale + nMaxDigits); - FormatNumber(ref sb, ref number, nMinDigits, nMaxDigits, info); + FormatNumber(ref sb, ref number, nMaxDigits, info); break; } @@ -1520,9 +1511,7 @@ namespace System case 'e': { if (nMaxDigits < 0) - nMaxDigits = nMinDigits = 6; - else - nMinDigits = nMaxDigits; + nMaxDigits = 6; nMaxDigits++; RoundNumber(ref number, nMaxDigits); @@ -1530,7 +1519,7 @@ namespace System if (number.sign) sb.Append(info.NegativeSign); - FormatScientific(ref sb, ref number, nMinDigits, nMaxDigits, info, format); + FormatScientific(ref sb, ref number, nMaxDigits, info, format); break; } @@ -1538,40 +1527,34 @@ namespace System case 'G': case 'g': { - bool enableRounding = true; + bool noRounding = false; if (nMaxDigits < 1) { if (isDecimal && (nMaxDigits == -1)) { - // Default to 29 digits precision only for G formatting without a precision specifier - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = DecimalPrecision; - enableRounding = false; // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant + noRounding = true; // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant + if (number.digits[0] == 0) + { + // Minus zero should be formatted as 0 + goto SkipSign; + } + goto SkipRounding; } else { // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = number.precision; + nMaxDigits = number.precision; } } - else - nMinDigits = nMaxDigits; - if (enableRounding) // Don't round for G formatting without precision - RoundNumber(ref number, nMaxDigits); // This also fixes up the minus zero case - else - { - if (isDecimal && (number.digits[0] == 0)) - { - // Minus zero should be formatted as 0 - number.sign = false; - } - } + RoundNumber(ref number, nMaxDigits); // This also fixes up the minus zero case +SkipRounding: if (number.sign) sb.Append(info.NegativeSign); - FormatGeneral(ref sb, ref number, nMinDigits, nMaxDigits, info, (char)(format - ('G' - 'E')), !enableRounding); +SkipSign: + FormatGeneral(ref sb, ref number, nMaxDigits, info, (char)(format - ('G' - 'E')), noRounding); break; } @@ -1580,14 +1563,12 @@ namespace System case 'p': { if (nMaxDigits < 0) - nMaxDigits = nMinDigits = info.PercentDecimalDigits; - else - nMinDigits = nMaxDigits; + nMaxDigits = info.PercentDecimalDigits; number.scale += 2; RoundNumber(ref number, number.scale + nMaxDigits); - FormatPercent(ref sb, ref number, nMinDigits, nMaxDigits, info); + FormatPercent(ref sb, ref number, nMaxDigits, info); break; } @@ -1954,7 +1935,7 @@ namespace System } } - private static void FormatCurrency(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info) + private static void FormatCurrency(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info) { string fmt = number.sign ? s_negCurrencyFormats[info.CurrencyNegativePattern] : @@ -1965,7 +1946,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.currencyGroupSizes, info.CurrencyDecimalSeparator, info.CurrencyGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info.currencyGroupSizes, info.CurrencyDecimalSeparator, info.CurrencyGroupSeparator); break; case '-': sb.Append(info.NegativeSign); @@ -1980,7 +1961,7 @@ namespace System } } - private static unsafe void FormatFixed(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup) + private static unsafe void FormatFixed(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, int[] groupDigits, string sDecimal, string sGroup) { int digPos = number.scale; char* dig = number.digits; @@ -2082,7 +2063,7 @@ namespace System } } - private static void FormatNumber(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info) + private static void FormatNumber(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info) { string fmt = number.sign ? s_negNumberFormats[info.NumberNegativePattern] : @@ -2093,7 +2074,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.numberGroupSizes, info.NumberDecimalSeparator, info.NumberGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info.numberGroupSizes, info.NumberDecimalSeparator, info.NumberGroupSeparator); break; case '-': sb.Append(info.NegativeSign); @@ -2105,7 +2086,7 @@ namespace System } } - private static unsafe void FormatScientific(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar) + private static unsafe void FormatScientific(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, char expChar) { char* dig = number.digits; @@ -2142,7 +2123,7 @@ namespace System sb.Append(p, (int)(digits + MaxUInt32DecDigits - p)); } - private static unsafe void FormatGeneral(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info, char expChar, bool bSuppressScientific) + private static unsafe void FormatGeneral(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info, char expChar, bool bSuppressScientific) { int digPos = number.scale; bool scientific = false; @@ -2189,7 +2170,7 @@ namespace System FormatExponent(ref sb, info, number.scale - 1, expChar, 2, true); } - private static void FormatPercent(ref ValueStringBuilder sb, ref NumberBuffer number, int nMinDigits, int nMaxDigits, NumberFormatInfo info) + private static void FormatPercent(ref ValueStringBuilder sb, ref NumberBuffer number, int nMaxDigits, NumberFormatInfo info) { string fmt = number.sign ? s_negPercentFormats[info.PercentNegativePattern] : @@ -2200,7 +2181,7 @@ namespace System switch (ch) { case '#': - FormatFixed(ref sb, ref number, nMinDigits, nMaxDigits, info, info.percentGroupSizes, info.PercentDecimalSeparator, info.PercentGroupSeparator); + FormatFixed(ref sb, ref number, nMaxDigits, info, info.percentGroupSizes, info.PercentDecimalSeparator, info.PercentGroupSeparator); break; case '-': sb.Append(info.NegativeSign); diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.cs index 0448837..045a40b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/ValueStringBuilder.cs @@ -132,7 +132,7 @@ namespace System.Text public void Append(char c) { int pos = _pos; - if (pos < _chars.Length) + if ((uint)pos < (uint)_chars.Length) { _chars[pos] = c; _pos = pos + 1; @@ -147,7 +147,7 @@ namespace System.Text public void Append(string s) { int pos = _pos; - if (s.Length == 1 && pos < _chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. + if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. { _chars[pos] = s[0]; _pos = pos + 1; -- 2.7.4