【发布时间】:2016-06-05 19:24:26
【问题描述】:
我注意到decimal.Parse(number, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture) 比基于来自Faster alternative to Convert.ToDouble 的 Jeffrey Sax 的代码的自定义十进制解析方法慢约 100%
public static decimal ParseDecimal(string input) {
bool negative = false;
long n = 0;
int len = input.Length;
int decimalPosition = len;
if (len != 0) {
int start = 0;
if (input[0] == '-') {
negative = true;
start = 1;
}
for (int k = start; k < len; k++) {
char c = input[k];
if (c == '.') {
decimalPosition = k +1;
} else {
n = (n *10) +(int)(c -'0');
}
}
}
return new decimal(((int)n), ((int)(n >> 32)), 0, negative, (byte)(len -decimalPosition));
}
我认为这是因为原生 decimal.Parse 旨在与数字风格和文化信息作斗争。
但是,上述方法不使用new decimal 中的第三个参数高字节,因此它不适用于更大的数字。
有没有比decimal.Parse 更快的替代方法来将仅由数字和小数点组成的字符串转换为适用于大数字的十进制?
编辑:基准测试:
var style = System.Globalization.NumberStyles.AllowDecimalPoint;
var culture = System.Globalization.CultureInfo.InvariantCulture;
System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
s.Reset();
s.Start();
for (int i=0; i<10000000; i++)
{
decimal.Parse("20000.0011223344556", style, culture);
}
s.Stop();
Console.WriteLine(s.Elapsed.ToString());
s.Reset();
s.Start();
for (int i=0; i<10000000; i++)
{
ParseDecimal("20000.0011223344556");
}
s.Stop();
Console.WriteLine(s.Elapsed.ToString());
输出:
00:00:04.2313728
00:00:01.4464048
在这种情况下,自定义 ParseDecimal 比 decimal.Parse 快得多。
【问题讨论】:
-
还应该考虑负数吗?
-
WillemVanOnsem Van Onsem,在我当前的用例中,我不需要负数。但是,这是一个对任何人都可能有用的一般性问题,因此如果它支持负数会更好。
-
Decimal.Parse() 在过去 20 年里用 C++ 编写并内置到操作系统中,速度达到了它需要的速度。你只能通过偷工减料来加快速度。你没有足够明确你认为什么样的错误是可以接受的。
-
输入值的统计分布是您想要优化的朋友。例如,如果大多数输入值以 1 字符串的形式出现,那么您可以为这种情况编写更简单/更快的转换代码(您甚至不必处理符号字符)。如果负值不常见,只转换正值的代码会更快;您可能必须测试一次符号,但如果不存在,您不必再次测试它的值。我会查看您的输入值分布,看看您是否不能利用它。
-
恕我直言,这属于Code Review
标签: c# performance parsing decimal