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

本文关键字:双精度 字符 缓冲区 字节 | 更新日期: 2023-09-27 17:54:20

在我的代码中,我需要将整数的字符串表示形式转换为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编码的数据。数字可以是负数。对于双精度值,允许使用指数格式。不允许十六进制整数

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

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

你可以很容易地将每个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(例如),那么它肯定会做错误的事情。

还要注意,这不会执行任何类型的长度验证或溢出检查…它不能处理负数。如果你想的话,你可以添加所有这些,但我们对你的需求了解不够,不知道是否值得添加这些复杂性。

我不确定是否有简单的方法可以做到这一点,请注意,它不会与其他编码工作,测试显示在我的电脑上,这是只有3倍快(我不认为它值得)。

代码+ test:

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;
    }
}

最后,我创建了c#版本的strol函数。该函数随CRT自带,CRT的源代码随Visual Studio自带。

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

在我的例子中,所有的改变都被证明在速度和内存方面非常有用。