这个产生超大数字的 C 乘法的等效 Delphi 代码是什么?
What is the equivalent Delphi code to this C multiplication that yields an oversized number?
这个问题的背景是...我正在尝试从Wikipedia: Hamming weight中移植C函数int popcount_3(uint64_t x)
,但是它的算法不是这个问题的重点。
假设x
是无符号64位值的最大个数(即x = 18446744073709551615),在计算结束时,C代码将计算:
uint64_t iResult = 578721382704613384ull * 72340172838076673ull;
首先我怀疑C代码引发了溢出错误,因为使用浮点乘法运算时的actual/real结果等于41864804849942400000000000000000000,但实际上,该C代码没有编译错误。输出为 4627501566018457608.
我们知道,上述 C 代码的 Delphi 代码为:
iResult := UInt64(578721382704613384) * UInt64(72340172838076673);
Delphi 编译器引发错误 E2099 转换或算术运算溢出。好的,我看到错误是合理的。
所以,我的问题是...什么是等效的 Delphi 大数乘法代码,使得 Delphi 给出与 C 中相同的结果?
稍后添加
为了预测即将到来的潜在问题"Why did I provide the example using a true constant expression?",原因是我想创建一个真正的常量来计算通过计算 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;
}
Delphi 64 位 XE3 Windows 编译器模式
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;
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}
然而,更好的方法是使用已经计算出的期望结果,然后使用这些技巧。
这个问题的背景是...我正在尝试从Wikipedia: Hamming weight中移植C函数int popcount_3(uint64_t x)
,但是它的算法不是这个问题的重点。
假设x
是无符号64位值的最大个数(即x = 18446744073709551615),在计算结束时,C代码将计算:
uint64_t iResult = 578721382704613384ull * 72340172838076673ull;
首先我怀疑C代码引发了溢出错误,因为使用浮点乘法运算时的actual/real结果等于41864804849942400000000000000000000,但实际上,该C代码没有编译错误。输出为 4627501566018457608.
我们知道,上述 C 代码的 Delphi 代码为:
iResult := UInt64(578721382704613384) * UInt64(72340172838076673);
Delphi 编译器引发错误 E2099 转换或算术运算溢出。好的,我看到错误是合理的。
所以,我的问题是...什么是等效的 Delphi 大数乘法代码,使得 Delphi 给出与 C 中相同的结果?
稍后添加
为了预测即将到来的潜在问题"Why did I provide the example using a true constant expression?",原因是我想创建一个真正的常量来计算通过计算 High(NativeUInt)
.
重现步骤
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;
}
Delphi 64 位 XE3 Windows 编译器模式
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;
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}
然而,更好的方法是使用已经计算出的期望结果,然后使用这些技巧。