更快的替代decimal.Parse [英] Faster alternative to decimal.Parse

查看:180
本文介绍了更快的替代decimal.Parse的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到 decimal.Parse(数字,NumberStyles.AllowDecimalPoint,CultureInfo.InvariantCulture)比定制小数解析方法要慢约100%的基础上,从<一杰弗里·萨克斯的代码HREF =http://stackoverflow.com/questions/8457934/faster-alternative-to-convert-todouble>更快的替代Convert.ToDouble

I noticed decimal.Parse(number, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture) is about 100% slower than custom decimal parse method based on Jeffrey Sax's code from Faster alternative to Convert.ToDouble

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 设计有一些风格和文化信息的斗争。

I assume that is because native decimal.Parse is designed to struggle with number style and culture info.

不过,上述方法不<$ C $使用第3个参数喜字节C>新小数所以不会有较大的数字工作。

However, above mentioned method doesn't use 3rd parameter hi byte in new decimal so it won't work with larger numbers.

有没有小数更快的替代方案。 ?解析来的字符串,仅由数字和小数点点,以十进制这将有大量的工作转换

Is there a faster alternative to decimal.Parse to convert string that consists only of numbers and decimal dot to decimal which would work with large numbers?

编辑:基准:

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());



输出:

output:

00:00:04.2313728
00:00:01.4464048

自定义ParseDecimal在这种情况下比decimal.Parse显著快。

Custom ParseDecimal is in this case significantly faster than decimal.Parse.

推荐答案

感谢您的意见这给了我一个小更深入的了解。最后我做到了如下。如果输入太长,那么它分开输入字符串,并使用长和INT剩下的这仍然比decimal.Parse更快的解析第一部分。

Thanks for all your comments which gave me a little more insight. Finally I did it as follows. If input is too long then it separates input string and parses first part using long and the rest with int which is still faster than decimal.Parse.

这是我最后的生产代码:

This is my final production code:

public static int[] powof10 = new int[10]
{
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000
};
public static decimal ParseDecimal(string input)
{
    int len = input.Length;
    if (len != 0)
    {
        bool negative = false;
        long n = 0;
        int start = 0;
        if (input[0] == '-')
        {
            negative = true;
            start = 1;
        }
        if (len <= 19)
        {
            int decpos = len;
            for (int k = start; k < len; k++)
            {
                char c = input[k];
                if (c == '.')
                {
                    decpos = k +1;
                }else{
                    n = (n *10) +(int)(c -'0');
                }
            }
            return new decimal((int)n, (int)(n >> 32), 0, negative, (byte)(len -decpos));
        }else{
            if (len > 28)
            {
                len = 28;
            }
            int decpos = len;
            for (int k = start; k < 19; k++)
            {
                char c = input[k];
                if (c == '.')
                {
                    decpos = k +1;
                }else{
                    n = (n *10) +(int)(c -'0');
                }
            }
            int n2 = 0;
            bool secondhalfdec = false; 
            for (int k = 19; k < len; k++)
            {
                char c = input[k];
                if (c == '.')
                {
                    decpos = k +1;
                    secondhalfdec = true;
                }else{
                    n2 = (n2 *10) +(int)(c -'0');
                }
            }
            byte decimalPosition = (byte)(len -decpos);
            return new decimal((int)n, (int)(n >> 32), 0, negative, decimalPosition) *powof10[len -(!secondhalfdec ? 19 : 20)] +new decimal(n2, 0, 0, negative, decimalPosition);
        }
    }
    return 0;
}



基准代码:

benchmark code:

const string input = "[inputs are below]";
var style = System.Globalization.NumberStyles.AllowDecimalPoint | System.Globalization.NumberStyles.AllowLeadingSign;
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(input, style, culture);
}
s.Stop();
Console.WriteLine(s.Elapsed.ToString());

s.Reset();
s.Start();
for (int i=0; i<10000000; i++)
{
    ParseDecimal(input);
}
s.Stop();
Console.WriteLine(s.Elapsed.ToString());

这是我的酷睿i7 920的结果:

results on my i7 920:

输入:123.456789

input: 123.456789

00:00:02.7292447
00:00:00.6043730

输入:999999999999999123.456789

input: 999999999999999123.456789

00:00:05.3094786
00:00:01.9702198

输入:1.0

00:00:01.4212123
00:00:00.2378833

输入:0

00:00:01.1083770
00:00:00.1899732

输入:-3.3333333333333333333333333333333

input: -3.3333333333333333333333333333333

00:00:06.2043707
00:00:02.0373628

如果输入只包含0-9。和可选的 - 在开始时那么这个自定义函数显著更快解析字符串到十进制

If input consists only of 0-9, . and optionally - at the begining then this custom function is significantly faster for parsing string to decimal.

这篇关于更快的替代decimal.Parse的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆