Result:= b8;
Result:= Result+ (b7 SHL 8);
Result:= Result+ (b6 SHL 16);
Result:= Result+ (b5 SHL 24);
Result:= Result+ (b4 SHL 32);
Result:= Result+ (b3 SHL 40); <------ here
Result:= Result+ (b2 SHL 48);
Result:= Result+ (MSB SHL 56);
Run Code Online (Sandbox Code Playgroud)
(结果为int64,b1-b8为字节).
但是编译器抱怨"常量exp违反了子范围".然后我发现了这个警告"编译器将拒绝超过32的硬编码移位权限值,除非数据类型是Int64.对于网站上的Shl"也是如此.Delphi Help对此一无所知.为什么有限制?我可以阻止它吗?也许编译器指令或什么?我可以使用乘法来克服它,但速度会慢一些.有更快的方法吗?
编辑:我也想创建两个红衣主教,因为我可以在红衣主教上使用SHL,然后将红衣主教合并在一起.这只需要一次乘法.还有其他想法吗?
编辑2:代码是算法的一部分,该算法将数字形式基数255转换为基数256(反之亦然).我这样做了5亿次; 所以速度很重要.
Dav*_*nan 17
我会避免所有算术(你的代码有添加和移位),并这样做:
Int64Rec(Result).Bytes[0] := b8;
Int64Rec(Result).Bytes[1] := b7;
//etc.
Run Code Online (Sandbox Code Playgroud)
Int64Rec 在SysUtils中定义如下:
Int64Rec = packed record
case Integer of
0: (Lo, Hi: Cardinal);
1: (Cardinals: array [0..1] of Cardinal);
2: (Words: array [0..3] of Word);
3: (Bytes: array [0..7] of Byte);
end;
Run Code Online (Sandbox Code Playgroud)
如果您将字节存储在一个数组中,那么您可以将它全部包装在一个for循环中.
Ond*_*lle 11
我假设你Result是Int64已经,并且b8,b7等被声明为Byte.编译器需要一些帮助.Typecast Int64:
Result := b8;
Result := Result + (b7 shl 8);
Result := Result + (b6 shl 16);
Result := Result + (b5 shl 24);
Result := Result + (Int64(b4) shl 32);
Result := Result + (Int64(b3) shl 40);
Result := Result + (Int64(b2) shl 48);
Result := Result + (Int64(msb) shl 56);
Run Code Online (Sandbox Code Playgroud)
这是另一个使用轮班的解决方案,但我认为是"更干净"(尽管不像大卫的建议那样干净):
result := MSB;
result := (result shl 8) or b2; { could use "shl sizeof(b2)" instead of 8 }
result := (result shl 8) or b3;
etc
result := (result shl 8) or b8;
Run Code Online (Sandbox Code Playgroud)
这个解决方案避免了所有"神奇"的移动值,它可能更容易理解.此外,如果MSB..b8(或b1..b8)是一个字节数组,则上述代码可以很容易地转换为单行循环.
要回答关于为什么编译器不接受40及以上值的问题,原因很可能是由于SHLD指令的英特尔指令集参考文献第2B卷的引用:
在非64位模式和默认的64位模式下; 仅使用计数的第0位到第4位.这会将计数屏蔽为0到31之间的值.如果计数大于操作数大小,则结果是未定义的.
SHL指令的等效条件不是那么严格:
8086不掩盖班次计数.但是,所有其他IA-32处理器(从Intel 286处理器开始)确实将移位计数屏蔽为5位,最大计数为31.此屏蔽在所有操作模式(包括虚拟8086模式)下完成减少指令的最大执行时间.
在任何一种情况下,大于31的值都是无用的(使用SHL时)或未定义的(使用SHLD时).编译器显然知道这一点,并且它阻止您编写可能错误的代码(在64位模式下).
如果你确实在这个操作上进行了50亿次,那么你可能要考虑在内联汇编中进行,这很简单:
asm
xor eax, eax
or eax, MSB { or b1 depending on how you named the MSB }
shl eax, 8
or eax, b2
shl eax, 8
or eax, b3
shl eax, 8
or eax, b4
mov High32bit, eax
end;
Run Code Online (Sandbox Code Playgroud)
并对低32位双字和b5至b8重复上述操作.我没有建议使用SHLD,因为我不相信Delphi支持64位寄存器或64位指令(我可能错了,我从未尝试过.)
注意:我听说有传言称64位版本的Delphi不支持内联汇编.这可能是也可能不是这样,但我会远离内联汇编,除非它确实是绝对必要的.
希望有所帮助,
约翰.
PS:David Heffernan的解决方案是最好的解决方案还有另外一个原因.在我提出的解决方案中,每条指令都依赖于前一条指令(即,在执行下一条"或"指令之前,eax必须移位8).David的解决方案设置单个字节,因此,每个分配独立于先前的分配,这将允许处理器并行地执行多个分配.在这个多核处理器的时代,这有可能比我给出的汇编代码快一点.
| 归档时间: |
|
| 查看次数: |
3057 次 |
| 最近记录: |