Convert.ToDouble的更快替代品

是否存在将String转换为DoubleConvert.ToDouble 更快的方法?

我监视过System.Convert.ToDouble(String)调用并降低了我的应用程序性能。

Convert.ToDouble("1.34515"); 

Perfomance截图

Jeffrey Sax的工作答案:

 static decimal[] decimalPowersOf10 = { 1m, 10m, 100m, 1000m, 10000m, 100000m, 1000000m }; static decimal CustomParseDecimal(string input) { long n = 0; int decimalPosition = input.Length; for (int k = 0; k < input.Length; k++) { char c = input[k]; if (c == '.') decimalPosition = k + 1; else n = (n * 10) + (int)(c - '0'); } return n / decimalPowersOf10[input.Length - decimalPosition]; 

}

在Jeffrey Sax CustomParser之后

通过使用NumberStylesIFormatProvider特定缓存实例(即CultureInfo )调用Double.TryParse ,可以节省大约10%:

 var style = System.Globalization.NumberStyles.AllowDecimalPoint; var culture = System.Globalization.CultureInfo.InvariantCulture; double.TryParse("1.34515", style, culture, out x); 

Convert.ToDoubleDouble.ParseDouble.TryParse都必须假设输入可以是任何格式。 如果您确定您的输入具有特定格式,则可以编写一个性能更好的自定义解析器。

这是一个转换为decimal 。 转换为double是类似的。

 static decimal CustomParseDecimal(string input) { long n = 0; int decimalPosition = input.Length; for (int k = 0; k < input.Length; 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, false, (byte)(input.Length - decimalPosition)); } 

我的基准测试显示,这比原来的decimal快了大约5倍,如果使用整数,则高达12倍。

我无法重现这一点。 此代码测试Convert.ToDouble的速度。

  int numTests = 10000; double sum = 0; var sw = Stopwatch.StartNew(); for (int i = 0; i < numTests; ++i) { var d = Convert.ToDouble("1.23456"); sum += d; } sw.Stop(); Console.WriteLine("{0} tests @ {1} ms. Avg of {2:N4} ms each", numTests, sw.ElapsedMilliseconds, (double)sw.ElapsedMilliseconds/numTests); Console.WriteLine("sum = {0}", sum); 

有10,000个电话,我明白了

 10000 tests @ 3 ms. Avg of 0.0003 ms each sum = 12345.6000000021 

那是在发布模式下,在没有连接调试器的情况下运行。

Convert.ToDouble问题的可能性Convert.ToDouble

你可以调用double.Parse("1.34515"); 这是Convert.ToDouble包装的内容。

调用double.TryParse可能会更快,这将避免exception开销。

您可以尝试通过使用Double.Parse(String, NumberStyles, IFormatProvider) 重载来减少对Thread.CurrentCulture的调用次数。 虽然我怀疑它会产生重大影响。

解析为另一种类型可能会发生: floatdecimal可能会赢得几个百分点。

有点疯狂,但是……你可以缓存NumberFormatInfo实例并使用reflection直接调用内部System.Number.ParseDouble 。 这会减少对NumberFormatInfo.GetInstance()的调用次数,但说实话,我希望reflection速度要慢得多。

剩下的唯一选择(除了避免解析)是使用一些自定义解析方法。 例如,如果您为数字定义了严格的格式(例如#.#### ),您可能最终会得到更快,更灵活和/或更安全的实现。 但考虑到内置解析是半原生的,我怀疑你会赢。

UPDATE

我对.NET代码进行了更多的分析,发现NumberFormatInfo是一个IFormatProvider 。 所以似乎最快的代码应该是:

 IFormatProvider _CachedProvider = NumberFormatInfo.CurrentInfo; var value1 = double.Parse(str1, NumberStyles.Number, _CachedProvider); var value2 = double.Parse(str2, NumberStyles.Number, _CachedProvider); 

此代码应尽可能减少解析准备所花费的时间。 如果你解析很多字符串对,你也可以将IFormatProvider缓存提取到一个外部代码(可能)运行一个循环并赢得另外几毫秒。

double.Parse()应该快一点。

如果您100%确定源数据格式范围,可以使用:

 string num = "1.34515"; int len = num.Length - num.IndexOf('.') - 1; int intval = Int32.Parse(num.Replace(".", "")); double d = (double)intval / PowersOf10[len]; // PowersOf10 is pre-computed or inlined 

它对我来说比Double.Parse快了大约50%,但我不会在任何严肃的应用程序中使用它 – 与正确的解析相比它非常有限,我无法想到你需要解析数百万双打的过程几毫秒就会有所不同。

这篇文章中的函数更快的十进制替代.Parse基于Jeffrey Sax的代码。 它增加了对负数的支持,通过缓存input来优化性能.Length变为变量,也适用于较大的数字。