这个问题的背景是......我试图从Wikipedia: Hamming weight移植C函数int popcount_3(uint64_t x)
,但它的算法不是这个问题的焦点。
我们说x
是无符号64位值的最大数量(即 x = 18446744073709551615 ),在计算结束时,C代码将计算:
uint64_t iResult = 578721382704613384ull * 72340172838076673ull;
首先我怀疑C代码引发了溢出错误,因为使用浮点乘法时操作的实际/实际结果等于 41864804849942400000000000000000000 ,但事实上,没有编译该C代码的错误。输出 4627501566018457608 。
我们知道,上面C代码的Delphi代码是:
iResult := UInt64(578721382704613384) * UInt64(72340172838076673);
Delphi编译器在转换或算术运算中引发错误 E2099溢出。好的,我看到错误是合理的。
所以,我的问题是......超大数字乘法的等效Delphi代码是什么,以便Delphi给出与C相同的结果?
预测即将发生的潜在问题"为什么我使用真正的常量表达式提供示例?" ,原因是我想要创建真常量,通过计算High(NativeUInt)
中的设置位数来计算computer word中的位数。
GCC 4.8.1(MinGW)
#include <stdio.h>
#include <stdint.h>
int main () {
uint64_t iResult = 578721382704613384ull * 72340172838076673ull;
printf("iResult = %llu\n", iResult); // output --> 4627501566018457608
return 0;
}
64位Windows编译模式下的Delphi XE3
procedure Test;
var
iResult : UInt64;
RealResult: Double;
begin
iResult := UInt64(578721382704613384) * UInt64(72340172838076673);
RealResult := 578721382704613384.0 * 72340172838076673.0;
WriteLn('iResult = ', iResult); // error --> E2099 Overflow in ...
WriteLn('RealResult = ', RealResult); // output --> 4.18648048499424E+0034
end;
答案 0 :(得分:3)
Delphi编译器尝试在编译时计算常量表达式UInt64(578721382704613384) * UInt64(72340172838076673)
,并向您报告溢出错误。
解决方案是使用变量:
var
iResult, i1, i2 : UInt64;
RealResult: Double;
begin
i1 := 578721382704613384;
i2 := 72340172838076673;
iResult := i1 * i2;
RealResult := 578721382704613384.0 * 72340172838076673.0;
此代码产生所需的结果。
请注意,项目选项中的Overflow check
标志必须处于关闭状态。或者在代码中使用编译器指令,如
{$OVERFLOWCHECKS OFF}
iResult := i1 * i2;
{$OVERFLOWCHECKS ON}
修改基于@ hvd的警告
这些指令只有在项目的选项Overflow check
为On
的情况下才有意义。如果没有,那些指令可以省略。
第三种方式,最常见和最普遍的方法是使用{$ ifopt ...}指令(@hvd,再次感谢):
{$ifopt Q+} // If option is On ...
{$Q-} // then turn it Off ...
{$define TURNQON} // and keep in mind that it must be restored
{$endif}
iResult := i1 * i2;
{$ifdef TURNQON}{$Q+}{$undef TURNQON}{$endif}
然而,更好的方法是使用已经计算过的所需结果然后使用这些技巧。