简体   繁体   English

更快的替代 Convert.ToDouble(string)

[英]Faster alternative to Convert.ToDouble(string)

Is there a faster way to convert a string to double than Convert.ToDouble ?有没有比Convert.ToDouble更快的string转换为double

I have monitored System.Convert.ToDouble(string) calls and its degrading my app performance.我已经监控了System.Convert.ToDouble(string)调用及其降低了我的应用程序性能。

Convert.ToDouble("1.34515");

性能截图

WORKING ANSWER FROM 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 之后

You can save about 10% by calling Double.TryParse with specific cached instances of NumberStyles and IFormatProvider (ie CultureInfo ):通过使用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);

Both Convert.ToDouble and Double.Parse or Double.TryParse have to assume the input can be in any format. Convert.ToDoubleDouble.ParseDouble.TryParse都必须假设输入可以是任何格式。 If you know for certain that your input has a specific format, you can write a custom parser that performs much better.如果您确定您的输入具有特定格式,您可以编写一个性能更好的自定义解析器。

Here's one that converts to decimal .这是一个转换为decimal Conversion to double is similar.转换为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));
}

My benchmarks show this to be about 5 times faster than the original for decimal , and up to 12 times if you use ints.我的基准测试表明这比原始的decimal快约 5 倍,如果使用 ints 则高达 12 倍。

I'm unable to reproduce this.我无法重现这一点。 This code tests the speed of Convert.ToDouble .此代码测试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);

With 10,000 calls, I get通过 10,000 个电话,我得到

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

That's in release mode, running without the debugger attached.这是在发布模式下,在没有附加调试器的情况下运行。

It's highly unlikely that the problem is with Convert.ToDouble .问题极不可能出在Convert.ToDouble

You can call double.Parse("1.34515");你可以调用double.Parse("1.34515"); which is what Convert.ToDouble wraps.这就是Convert.ToDouble包装的内容。

It may be quicker to call double.TryParse which will avoid the exception overhead.调用double.TryParse可能会更快,这将避免异常开销。

Function in this post Faster alternative to decimal.Parse is based on Jeffrey Sax's code.这篇文章中的函数Faster替代decimal.Parse基于Jeffrey Sax的代码。 It adds support for negative numbers, optimizes performance by caching input.Length into a variable and works also for larger numbers.它增加了对负数的支持,通过将 input.Length 缓存到变量中来优化性能,并且也适用于更大的数字。

You could try decreasing the number of calls to Thread.CurrentCulture by using the Double.Parse(String, NumberStyles, IFormatProvider) overload .您可以尝试使用Double.Parse(String, NumberStyles, IFormatProvider)重载来减少对Thread.CurrentCulture的调用次数。 Although I doubt it would make a significant difference.虽然我怀疑这会产生重大影响。

It may occur that parsing to another type: float or decimal may win a couple percent.可能会发生解析为另一种类型: floatdecimal可能会赢得几个百分比。

Kind of a mad idea, but... You could cache the NumberFormatInfo instance and use reflection to call the internal System.Number.ParseDouble directly.有点疯狂的想法,但是...您可以缓存NumberFormatInfo实例并使用反射直接调用内部System.Number.ParseDouble This would decrease the number of calls to NumberFormatInfo.GetInstance() , but to be honest, I'd expect reflection to be much slower.这会减少对NumberFormatInfo.GetInstance()的调用次数,但老实说,我希望反射会慢得多。

The only option left (except for avoiding parsing) is using some custom parsing method.剩下的唯一选择(避免解析除外)是使用一些自定义解析方法。 For example, if you define a strict format for the numbers (eg #.#### ), you could probably end up with a faster, yet less flexible and/or safe implementation.例如,如果您为数字定义了严格的格式(例如#.#### ),您可能最终会得到一个更快但不太灵活和/或安全的实现。 But taking into account that built-in parsing is half-native, I doubt you'll win.但考虑到内置解析是半原生的,我怀疑你会赢。

UPDATE更新

I've analyzed the .NET code a bit more and found out that NumberFormatInfo is a IFormatProvider .我对 .NET 代码进行了更多分析,发现NumberFormatInfo是一个IFormatProvider So it seems like the fastest code should be:所以看起来最快的代码应该是:

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

This code should decrease the time spent for parsing preparation as much as it's possible.此代码应尽可能减少解析准备所花费的时间。 If you parse a lot of string pairse, you could also extract the IFormatProvider caching to an external code that (possibly) runs a loop and win another couple of milliseconds.如果您解析大量字符串对,您还可以将IFormatProvider缓存提取到(可能)运行循环并赢得另外几毫秒的外部代码。

double.Parse()应该快一点。

If you are 100% sure about your source data format and range, you can use:如果您 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

It worked ~50% faster than Double.Parse for me, but I wouldn't use it in any serious applications - it's extremely limited compared to proper parsing and I can't think of process where you need to parse millions of doubles and a few milliseconds would make the difference.对我来说,它比Double.Parse快约 50%,但我不会在任何严肃的应用程序中使用它 - 与正确的解析相比,它非常有限,我想不出需要解析数百万双打和一个的过程几毫秒就会有所作为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM