The background for this question is ... I'm trying to port the C function int popcount_3(uint64_t x)
from the Wikipedia: Hamming weight, but its algorithm is not the focus of this question.
Let's say x
is the maximum number of unsigned 64-bit value (that is x = 18446744073709551615), at the end of calculation, the C code will calculate:
uint64_t iResult = 578721382704613384ull * 72340172838076673ull;
Firstly I suspected the C code raised overflow error because the actual/real result of the operation when using floating-point multiplication equals 41864804849942400000000000000000000, but in fact, no compiling error for that C code. The output is 4627501566018457608.
As we know, the Delphi code for the above C code would be:
iResult := UInt64(578721382704613384) * UInt64(72340172838076673);
The Delphi compiler raise an error E2099 Overflow in conversion or arithmetic operation. OK, I see the error is reasonable.
So, my question is ... What is the equivalent Delphi code for the multiplication of oversized numbers such that Delphi gives the same result as in C?
To anticipate a coming potential question "Why did I provide the example using a true constant expression?", the reason is that I want to create a true constant that calculates the number of bits in the computer word by counting the number of set bits in 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 XE3 in 64-bit Windows compiler mode
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 compiler tries to calculate constant expression UInt64(578721382704613384) * UInt64(72340172838076673)
at compile time and reports about overflow error to you.
The solution is using variables:
var
iResult, i1, i2 : UInt64;
RealResult: Double;
begin
i1 := 578721382704613384;
i2 := 72340172838076673;
iResult := i1 * i2;
RealResult := 578721382704613384.0 * 72340172838076673.0;
This code produces desired result.
Note that Overflow check
flag in the project options must be off. Or use compiler directives in the code like
{$OVERFLOWCHECKS OFF}
iResult := i1 * i2;
{$OVERFLOWCHECKS ON}
Edit Based on @hvd's warning
Those directives have sense only in case if in a project's options Overflow check
is On
. If not, those directives can be omitted.
The third way, most commonly and universal, is using {$ifopt ...} directive (@hvd, thanks again):
{$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}
However the better way is using already calculated desired result then such tricks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With