字节/字符缓冲区为长和/或双

时间:2013-01-19 09:35:32

标签: c# performance bytearray c#-2.0

在我的代码中,我需要将整数的字符串表示形式转换为longdouble值。

字符串表示是一个字节数组(byte[])。例如,对于数字12345,字符串表示为{ 49, 50, 51, 52, 53 }

目前,我使用以下明显的代码转换为long(几乎相同的代码转换为double

private long bytesToIntValue()
{
    string s = System.Text.Encoding.GetEncoding("Latin1").GetString(bytes);
    return long.Parse(s, CultureInfo.InvariantCulture);
}

此代码按预期工作,但在我的情况下我想要更好的东西。这是因为我必须先将字节转换为字符串。

在我的情况下,bytesToIntValue()被调用大约1200万次,大约25%的内存分配是在这种方法中进行的。

当然,我想优化这部分。我想在没有中间字符串的情况下执行转换(+ speed, - allocation)。

你会推荐什么?如何在没有中间字符串的情况下执行转换?是否有更快的方法来执行转换?

修改

我正在处理的字节数组总是包含ASCII编码数据。数字可能是负数。对于double值,允许指数格式。不允许使用十六进制整数。

3 个答案:

答案 0 :(得分:3)

  

如何在没有中间字符串的情况下执行转换?

您可以轻松地将每个byte转换为char。例如 - 未经测试:

private static long ConvertAsciiBytesToInt32(byte[] bytes)
{
    long value = 0;
    foreach (byte b in bytes)
    {
        value *= 10L;
        char c = b; // Implicit conversion; effectively ISO-8859-1
        if (c < '0' || c > '9')
        {
            throw new ArgumentException("Bytes contains non-digit: " + c);
        }
        value += (c - '0');
    }
    return value;
}

请注意,这真的 假设它是ASCII(或兼容) - 如果你的字节数组实际上是UTF-16(例如)那么它肯定会做错了。

另请注意,这不执行任何类型的长度验证或溢出检查......并且它不能处理负数。如果需要,您可以添加所有这些,但我们对您的要求知之甚少,不知道是否值得增加复杂性。

答案 1 :(得分:1)

我不确定有一种简单的方法可以做到这一点, 请注意,它不适用于其他编码,我的计算机上显示的测试只有3倍(我认为不值得)。

代码+测试:

class MainClass
{
    public static void Main(string[] args)
    {
        string str = "12341234";
        byte[] buffer = Encoding.ASCII.GetBytes(str);

        Stopwatch sw = Stopwatch.StartNew();
        for(int i = 0; i <   1000000 ;i ++)
        {
            long val = BufferToLong.GetValue(buffer);
        }
        Console.WriteLine (sw.ElapsedMilliseconds);
        sw.Restart();
        for (int i = 0 ; i < 1000000 ; i++)
        {
            string valStr = Encoding.ASCII.GetString(buffer);
            long val = long.Parse(valStr);
        }
        Console.WriteLine (sw.ElapsedMilliseconds);
    }
}

static class BufferToLong
{

    public static long GetValue(Byte[] buffer) {

        long number = 0;

        foreach (byte currentByte in buffer) {

            char currentChar = (char)currentByte;
            int currentDigit = currentChar - '0';

            number *= 10 ;
            number += currentDigit;

        }

        return number;
    }

}

答案 2 :(得分:0)

最后,我创建了strol函数的C#版本。此功能随CRT一起提供,CRT的源代码随Visual Studio一起提供。

结果方法与@Jon Skeet在他的回答中提供的代码几乎相同,但也包含一些溢出检查。

就我而言,所有这些变化在速度和记忆方面都非常有用。