这个C乘法的等效Delphi代码是什么产生了一个超大的数字?

时间:2015-09-05 08:10:20

标签: delphi delphi-xe3

这个问题的背景是......我试图从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;

1 个答案:

答案 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 checkOn的情况下才有意义。如果没有,那些指令可以省略。

第三种方式,最常见和最普遍的方法是使用{$ 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}

然而,更好的方法是使用已经计算过的所需结果然后使用这些技巧。