Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET上更快地解析数字_C#_Performance_Parsing_F# - Fatal编程技术网

C# 在.NET上更快地解析数字

C# 在.NET上更快地解析数字,c#,performance,parsing,f#,C#,Performance,Parsing,F#,我已经编写了两个函数,它们将一串空格分隔的整数转换为整数数组。第一个函数使用Substring,然后应用System.Int32.Parse将子字符串转换为int值: let intsOfString(s:string)= 设ints=ResizeArray() 让rec进入i j= 如果j=s.长度,则 ints.Add(s.Substring(i,j-i)|>System.Int32.Parse) 其他的 设c=s[j] 如果“0”不确定这是否有用,但您是否尝试过类似的方法: var str

我已经编写了两个函数,它们将一串空格分隔的整数转换为整数数组。第一个函数使用
Substring
,然后应用
System.Int32.Parse
将子字符串转换为
int
值:

let intsOfString(s:string)=
设ints=ResizeArray()
让rec进入i j=
如果j=s.长度,则
ints.Add(s.Substring(i,j-i)|>System.Int32.Parse)
其他的
设c=s[j]

如果“0”不确定这是否有用,但您是否尝试过类似的方法:

var stringValues = input.split(" ");

var intValues = Array.ConvertAll(stringValues, s => int.Parse(s));

我为double编写了这个函数,它不会创建临时子字符串。这意味着要在JSON解析器中使用,因此它将自己限制在如何根据需要在JSON中表示double

它还不是最优的,因为它要求您知道数字的开始和结束位置(
begin
end
参数),因此您必须遍历数字的长度两次才能找到数字的结束位置。它仍然比double.Parse快10-15倍左右,并且可以很容易地修改它,在函数中找到
end
,然后作为
out
参数返回,以知道必须在哪里继续解析主字符串

这样使用:

Parsers.TryParseDoubleFastStream("1", 0, 1, out j);
Parsers.TryParseDoubleFastStream("2.0", 0, 3, out j);
Parsers.TryParseDoubleFastStream("3.5", 0, 3, out j);
Parsers.TryParseDoubleFastStream("-4.5", 0, 4, out j);
Parsers.TryParseDoubleFastStream("50.06", 0, 5, out j);
Parsers.TryParseDoubleFastStream("1000.65", 0, 7, out j);
Parsers.TryParseDoubleFastStream("-10000.8600", 0, 11, out j);
代码可在此处找到:

(将太长,无法在此发布)

StandardFunctions.IgnoreChar
对于我来说非常简单:

public static bool IgnoreChar(char c)
{
  return c < 33;
}
公共静态bool IgnoreChar(char c)
{
返回c<33;
}

System.Int32.Parse
最慢,因为它使用了
CultureInfo
FormatInfo
等;而性能原因不在临时字符串中

来自反射的代码:

private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
    number.scale = 0;
    number.sign = false;
    string text = null;
    string text2 = null;
    string str2 = null;
    string str3 = null;
    bool flag = false;
    string str4;
    string str5;
    if ((options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None)
    {
        text = numfmt.CurrencySymbol;
        if (numfmt.ansiCurrencySymbol != null)
        {
            text2 = numfmt.ansiCurrencySymbol;
        }
        str2 = numfmt.NumberDecimalSeparator;
        str3 = numfmt.NumberGroupSeparator;
        str4 = numfmt.CurrencyDecimalSeparator;
        str5 = numfmt.CurrencyGroupSeparator;
        flag = true;
    }
    else
    {
        str4 = numfmt.NumberDecimalSeparator;
        str5 = numfmt.NumberGroupSeparator;
    }
    int num = 0;
    char* ptr = str;
    char c = *ptr;
    while (true)
    {
        if (!Number.IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == NumberStyles.None || ((num & 1) != 0 && ((num & 1) == 0 || ((num & 32) == 0 && numfmt.numberNegativePattern != 2))))
        {
            bool flag2;
            char* ptr2;
            if ((flag2 = (((options & NumberStyles.AllowLeadingSign) == NumberStyles.None) ? false : ((num & 1) == 0))) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                num |= 1;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    num |= 1;
                    number.sign = true;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (c == '(' && (options & NumberStyles.AllowParentheses) != NumberStyles.None && (num & 1) == 0)
                    {
                        num |= 3;
                        number.sign = true;
                    }
                    else
                    {
                        if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                        {
                            break;
                        }
                        num |= 32;
                        text = null;
                        text2 = null;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                }
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    int num2 = 0;
    int num3 = 0;
    while (true)
    {
        if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
        {
            num |= 4;
            if (c != '0' || (num & 8) != 0)
            {
                if (num2 < 50)
                {
                    number.digits[(IntPtr)(num2++)] = c;
                    if (c != '0' || parseDecimal)
                    {
                        num3 = num2;
                    }
                }
                if ((num & 16) == 0)
                {
                    number.scale++;
                }
                num |= 8;
            }
            else
            {
                if ((num & 16) != 0)
                {
                    number.scale--;
                }
            }
        }
        else
        {
            char* ptr2;
            if ((options & NumberStyles.AllowDecimalPoint) != NumberStyles.None && (num & 16) == 0 && ((ptr2 = Number.MatchChars(ptr, str4)) != null || (flag && (num & 32) == 0 && (ptr2 = Number.MatchChars(ptr, str2)) != null)))
            {
                num |= 16;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if ((options & NumberStyles.AllowThousands) == NumberStyles.None || (num & 4) == 0 || (num & 16) != 0 || ((ptr2 = Number.MatchChars(ptr, str5)) == null && (!flag || (num & 32) != 0 || (ptr2 = Number.MatchChars(ptr, str3)) == null)))
                {
                    break;
                }
                ptr = ptr2 - (IntPtr)2 / 2;
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    bool flag3 = false;
    number.precision = num3;
    number.digits[(IntPtr)num3] = '\0';
    if ((num & 4) != 0)
    {
        if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != NumberStyles.None)
        {
            char* ptr3 = ptr;
            c = *(ptr += (IntPtr)2 / 2);
            char* ptr2;
            if ((ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                c = *(ptr = ptr2);
            }
            else
            {
                if ((ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    c = *(ptr = ptr2);
                    flag3 = true;
                }
            }
            if (c >= '0' && c <= '9')
            {
                int num4 = 0;
                do
                {
                    num4 = num4 * 10 + (int)(c - '0');
                    c = *(ptr += (IntPtr)2 / 2);
                    if (num4 > 1000)
                    {
                        num4 = 9999;
                        while (c >= '0' && c <= '9')
                        {
                            c = *(ptr += (IntPtr)2 / 2);
                        }
                    }
                }
                while (c >= '0' && c <= '9');
                if (flag3)
                {
                    num4 = -num4;
                }
                number.scale += num4;
            }
            else
            {
                ptr = ptr3;
                c = *ptr;
            }
        }
        while (true)
        {
            if (!Number.IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == NumberStyles.None)
            {
                bool flag2;
                char* ptr2;
                if ((flag2 = (((options & NumberStyles.AllowTrailingSign) == NumberStyles.None) ? false : ((num & 1) == 0))) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                {
                    num |= 1;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                    {
                        num |= 1;
                        number.sign = true;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                    else
                    {
                        if (c == ')' && (num & 2) != 0)
                        {
                            num &= -3;
                        }
                        else
                        {
                            if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                            {
                                break;
                            }
                            text = null;
                            text2 = null;
                            ptr = ptr2 - (IntPtr)2 / 2;
                        }
                    }
                }
            }
            c = *(ptr += (IntPtr)2 / 2);
        }
        if ((num & 2) == 0)
        {
            if ((num & 8) == 0)
            {
                if (!parseDecimal)
                {
                    number.scale = 0;
                }
                if ((num & 16) == 0)
                {
                    number.sign = false;
                }
            }
            str = ptr;
            return true;
        }
    }
    str = ptr;
    return false;
}
public static int Parse(string s)
{
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}

internal unsafe static int ParseInt32(string s, NumberStyles style, NumberFormatInfo info)
{
    byte* stackBuffer = stackalloc byte[1 * 114 / 1];
    Number.NumberBuffer numberBuffer = new Number.NumberBuffer(stackBuffer);
    int result = 0;
    Number.StringToNumber(s, style, ref numberBuffer, info, false);
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
    {
        if (!Number.HexNumberToInt32(ref numberBuffer, ref result))
        {
            throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
        }
    }
    else
    {
        if (!Number.NumberToInt32(ref numberBuffer, ref result))
        {
            throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
        }
    }
    return result;
}

private unsafe static void StringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo info, bool parseDecimal)
{
    if (str == null)
    {
        throw new ArgumentNullException("String");
    }
    fixed (char* ptr = str)
    {
        char* ptr2 = ptr;
        if (!Number.ParseNumber(ref ptr2, options, ref number, info, parseDecimal) || ((ptr2 - ptr / 2) / 2 < str.Length && !Number.TrailingZeros(str, (ptr2 - ptr / 2) / 2)))
        {
            throw new FormatException(Environment.GetResourceString("Format_InvalidString"));
        }
    }
}
private不安全静态bool ParseNumber(ref char*str,numberstyle选项,ref Number.NumberBuffer Number,NumberFormatInfo numfmt,bool parseDecimal)
{
数字。比例=0;
number.sign=false;
字符串文本=空;
字符串text2=null;
字符串str2=null;
字符串str3=null;
布尔标志=假;
字符串str4;
字符串str5;
if((选项和NumberStyles.AllowCurrencySymbol)!=NumberStyles.None)
{
text=numfmt.CurrencySymbol;
如果(numfmt.ansiCurrencySymbol!=null)
{
text2=numfmt.ansiCurrencySymbol;
}
str2=numfmt.NumberDecimalSeparator;
str3=numfmt.NumberGroupSeparator;
str4=numfmt.CurrencyDecimalSeparator;
str5=numfmt.CurrencyGroupSeparator;
flag=true;
}
其他的
{
str4=numfmt.NumberDecimalSeparator;
str5=numfmt.NumberGroupSeparator;
}
int num=0;
char*ptr=str;
字符c=*ptr;
while(true)
{
如果(!Number.IsWhite(c)|(options&NumberStyles.allowreadingwhite)==NumberStyles.None | |((num&1)!=0&((num&1)==0 | |((num&32)==0&&numfmt.numberNegativePattern!=2)))
{
布尔flag2;
char*ptr2;
如果((flag2=((options&NumberStyles.allowReadingSign)==NumberStyles.None)?false:((num&1)==0))&&(ptr2=Number.MatchChars(ptr,numfmt.positiveSign))!=null)
{
num |=1;
ptr=ptr2-(IntPtr)2/2;
}
其他的
{
if(flag2&(ptr2=Number.MatchChars(ptr,numfmt.negativeSign))!=null)
{
num |=1;
number.sign=true;
ptr=ptr2-(IntPtr)2/2;
}
其他的
{
如果(c='('&&(options&NumberStyles.AllowParentheses)!=NumberStyles.None&&(num&1)==0)
{
num |=3;
number.sign=true;
}
其他的
{
if((text==null | | |(ptr2=Number.MatchChars(ptr,text))==null)和&(text2==null | |(ptr2=Number.MatchChars(ptr,text2))==null))
{
打破
}
num |=32;
text=null;
text2=null;
ptr=ptr2-(IntPtr)2/2;
}
}
}
}
c=*(ptr+=(IntPtr)2/2);
}
int num2=0;
int num3=0;
while(true)
{
如果((c>='0'&&c='a'&&c='a'&&c='0'&&c 1000)
{
num4=9999;
而(c>='0'&&c='0'&&c将所有代码粘贴到c#中,并调用
Test()
。这是使用C#直接在字符串数组上操作以解析数字的最接近的方法。它是为速度而不是优雅而构建的。
ParseInt
ParseFloat
函数是为OpenGL图形引擎创建的,用于从基于文本的3d模型导入向量。解析浮点是这方面的一个重要瓶颈过程。这是我能做的最快的

using System.Diagnostics;

    private void Test()
    {
        Stopwatch sw = new Stopwatch();
        StringBuilder sb = new StringBuilder();
        int iterations = 1000;

        // Build a string of 1000000 space separated numbers
        for (var n = 0; n < iterations; n++)
        {
            if (n > 0)
                sb.Append(' ');
            sb.Append(n.ToString());
        }

        string numberString = sb.ToString();

        // Time the process
        sw.Start();
        StringToInts(numberString, iterations);
        //StringToFloats(numberString, iterations);
        sw.Stop();
        long proc1 = sw.ElapsedMilliseconds;

        Console.WriteLine("iterations: {0} \t {1}ms", iterations, proc1);
    }

    private unsafe int[] StringToInts(string s, int length)
    {
        int[] ints = new int[length];
        int index = 0;
        int startpos = 0;

        fixed (char* pStringBuffer = s)
        {
            fixed (int* pIntBuffer = ints)
            {
                for (int n = 0; n < s.Length; n++)
                {
                    if (s[n] == ' ' || n == s.Length - 1)
                    {
                        if (n == s.Length - 1)
                            n++;
                        // pIntBuffer[index++] = int.Parse(new string(pStringBuffer, startpos, n - startpos));
                        pIntBuffer[index++] = ParseInt((pStringBuffer + startpos), n - startpos); 
                        startpos = n + 1;
                    }
                }
            }
        }

        return ints;
    }

    private unsafe float[] StringToFloats(string s, int length)
    {
        float[] floats = new float[length];
        int index = 0;
        int startpos = 0;

        fixed (char* pStringBuffer = s)
        {
            fixed (float* pFloatBuffer = floats)
            {
                for (int n = 0; n < s.Length; n++)
                {
                    if (s[n] == ' ' || n == s.Length - 1)
                    {
                        if (n == s.Length - 1)
                            n++;

                        pFloatBuffer[index++] = ParseFloat((pStringBuffer + startpos), n - startpos); // int.Parse(new string(pStringBuffer, startpos, n - startpos));
                        startpos = n + 1;
                    }
                }
            }
        }

        return floats;
    }

    public static unsafe int ParseInt(char* input, int len)
    {
        int pos = 0;           // read pointer position
        int part = 0;          // the current part (int, float and sci parts of the number)
        bool neg = false;      // true if part is a negative number

        int* ret = stackalloc int[1];

        while (pos < len && (*(input + pos) > '9' || *(input + pos) < '0') && *(input + pos) != '-')
            pos++;

        // sign
        if (*(input + pos) == '-')
        {
            neg = true;
            pos++;
        }

        // integer part
        while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
            part = part * 10 + (input[pos++] - '0');

        *ret = neg ? (part * -1) : part;
        return *ret;
    }

    public static unsafe float ParseFloat(char* input, int len)
    {
        //float ret = 0f;      // return value
        int pos = 0;           // read pointer position
        int part = 0;          // the current part (int, float and sci parts of the number)
        bool neg = false;      // true if part is a negative number

        float* ret = stackalloc float[1];

        // find start
        while (pos < len && (input[pos] < '0' || input[pos] > '9') && input[pos] != '-' && input[pos] != '.')
            pos++;

        // sign
        if (input[pos] == '-')
        {
            neg = true;
            pos++;
        }

        // integer part
        while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
            part = part * 10 + (input[pos++] - '0');

        *ret = neg ? (float)(part * -1) : (float)part;

        // float part
        if (pos < len && input[pos] == '.')
        {
            pos++;
            double mul = 1;
            part = 0;

            while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
            {
                part = part * 10 + (input[pos] - '0');
                mul *= 10; 
                pos++;
            }

            if (neg)
                *ret -= (float)part / (float)mul;
            else
                *ret += (float)part / (float)mul;

        }

        // scientific part
        if (pos < len && (input[pos] == 'e' || input[pos] == 'E'))
        {
            pos++;
            neg = (input[pos] == '-'); pos++;
            part = 0;
            while (pos < len && !(input[pos] > '9' || input[pos] < '0'))
            {
                part = part * 10 + (input[pos++] - '0');
            }

            if (neg)
                *ret /= (float)Math.Pow(10d, (double)part);
            else
                *ret *= (float)Math.Pow(10d, (double)part);
        }

        return (float)*ret;
    }
使用系统诊断;
专用无效测试()
{
秒表sw=新秒表();
StringBuilder sb=新的StringBuilder();
int迭代次数=1000次;
//构建一个由1000000个空格分隔的数字组成的字符串
对于(var n=0;n0)
某人附加(“”);
某人附加(n.ToString());
}
string numberString=sb.ToString();
//给过程计时
sw.Start();
StringToInts(数字字符串、迭代);
//StringToFloats(numberString,迭代);
sw.Stop();
长proc1=sw.ElapsedMilliseconds;
WriteLine(“迭代:{0}\t{1}ms”,迭代,proc1);
}
私有不安全int[]StringToInts(字符串s,int长度)
{
int[]ints=新的int[长度];
int指数=0;
int startpos=0;
F