在我的代码中,我需要将整数的字符串表示形式转换为long
和double
值。
字符串表示是一个字节数组(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值,允许指数格式。不允许使用十六进制整数。
答案 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在他的回答中提供的代码几乎相同,但也包含一些溢出检查。
就我而言,所有这些变化在速度和记忆方面都非常有用。