是否存在更快方式将 String 转换为 Double 而不是 Convert.ToDouble ?
我监视过System.Convert.ToDouble(String)调用及其降低我的应用程序性能。
Convert.ToDouble("1.34515");
杰弗里·萨克斯的工作答案:
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];
}
答案 0 :(得分:8)
通过使用Double.TryParse
和NumberStyles
的特定缓存实例IFormatProvider
调用CultureInfo
可以节省大约10%的费用:
var style = System.Globalization.NumberStyles.AllowDecimalPoint;
var culture = System.Globalization.CultureInfo.InvariantCulture;
double.TryParse("1.34515", style, culture, out x);
Convert.ToDouble
和Double.Parse
或Double.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倍。
答案 1 :(得分:3)
我无法重现这一点。此代码测试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
的可能性极小。
答案 2 :(得分:2)
你可以拨打double.Parse("1.34515");
Convert.ToDouble
包裹的double.TryParse
。
调用{{1}}可能会更快,这将避免异常开销。
答案 3 :(得分:1)
您可以尝试使用Thread.CurrentCulture
overload减少对Double.Parse(String, NumberStyles, IFormatProvider)
的来电次数。虽然我怀疑它会产生重大影响。
可能会解析为其他类型:float
或decimal
可能会赢得几个百分点。
有点疯狂,但是......你可以缓存NumberFormatInfo
实例并使用反射来直接调用内部System.Number.ParseDouble
。这会减少对NumberFormatInfo.GetInstance()
的调用次数,但说实话,我希望反射速度要慢得多。
剩下的唯一选择(除了避免解析)是使用一些自定义解析方法。例如,如果您为数字定义严格格式(例如#.####
),您可能最终会得到更快,但不太灵活和/或安全的实现。但考虑到内置解析是半原生的,我怀疑你会赢。
<强>更新强>
我对.NET代码进行了更多分析,发现NumberFormatInfo
是IFormatProvider
。所以似乎最快的代码应该是:
IFormatProvider _CachedProvider = NumberFormatInfo.CurrentInfo;
var value1 = double.Parse(str1, NumberStyles.Number, _CachedProvider);
var value2 = double.Parse(str2, NumberStyles.Number, _CachedProvider);
此代码应尽可能减少解析准备所花费的时间。如果你解析了很多字符串对,你也可以将IFormatProvider
缓存提取到一个外部代码,该外部代码可能会运行一个循环并赢得另外几毫秒。
答案 4 :(得分:1)
此帖Faster alternative to decimal.Parse中的功能基于Jeffrey Sax的代码。它增加了对负数的支持,通过缓存input来优化性能.Length变为变量,也适用于更大的数字。
答案 5 :(得分:0)
double.Parse()
应该快一点。
答案 6 :(得分:0)
如果您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%,但我不会在任何严肃的应用程序中使用它 - 与正确的解析相比,它是非常有限的,我无法想到你需要解析的进程数百万的双打和几毫秒就会有所不同。