我需要在64位cpu上取8位数字并将其向右移动8次。每次我移动数字我需要在它后面移动相同的8位数,这样我最终会重复8次相同的8位数。这最终会转移,添加8,转移添加8 ...等等,结果是40多个周期(如果我错了,请纠正我)。
有没有办法在1个循环中执行此操作(移位和复制),以便最终得到相同的值?
long _value = 0;
byte _number = 7;
for (int i = 0; i < 8; i++) {
_value = (_value << 8) + _number;
}
编辑:我正在尝试比较一组字符来检测关键字。我不能使用string.contains,因为字符串值可能跨越缓冲区的边界。此外,该应用程序必须在嵌入式ARM cpu以及桌面和服务器CPU上运行。内存使用和CPU周期非常重要。
答案 0 :(得分:6)
如今,执行指令的数量与执行它们所需的 cpu周期数之间没有直接联系。 您似乎也假设C#中的语句对应于单个程序集/ cpu指令,这也是错误的。
您的代码似乎正确执行了算法描述所说的内容(请注意,long已签名,使用 ulong 表示无符号行为)。
如果要使用专门的 cpu扩展(如mmx,sse等)可以在一条指令中执行add-shift-assignment,则需要使用汇编代码。但我不确定是否存在这样的具体指令。这可能取决于您拥有的CPU类型。
您不能将汇编代码与c#一起直接使用,但您可以将汇编与 c 一起使用(作为链接对象文件使用,使其成为内联汇编)。编译后的c代码可以在c#/ .net中使用 interop 。
但对你而言,第一个也是最重要的问题应该是:你想要完成什么?
我怀疑性能对您的应用程序至关重要,即使您应该诚实地问自己c#是否是达到目标的最佳语言。
答案 1 :(得分:4)
另一个想法是预先计算所有字节值的查找表。
var lu = new long[256];
// init
var n = 7;
var v = lu[n];
<强>更新强>
一些基准测试结果(以每100000000次迭代的毫秒数为单位):
展开的版本是:
long _value = 0;
byte _number = 7;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
不安全的版本是:
long _value = 0;
byte _number = 7;
byte* p = (byte*)&_value;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
遗憾地没有表演:(
查找只是对数组的读取。
全部为x64 / release编译。
答案 2 :(得分:3)
如果你希望它快,你至少可以展开你的循环:
ulong _value = 0;
byte _number = 7;
_value = _number;
_value = (_value << 8) + _value;
_value = (_value << 16) + _value;
_value = (_value << 32) + _value;
这也会减少分支。