这是我根据您的代码编写的 SSCCE。请注意控制台应用程序的使用。让生活变得更加简单。
{$APPTYPE CONSOLE}
uses
SysUtils;
var
currPercent, currGross, currCalcValue : Currency;
begin
currGross := 1182.42;
currPercent := 1.45;
currCalcValue := (currGross * (currPercent * StrToCurr('.01')));
Writeln(CurrToStr(currCalcValue));
Readln;
end.
现在查看生成的代码。第一个 32 位:
Project3.dpr.13: currCalcValue := (currGross * (currPercent * StrToCurr('.01')));
0041C409 8D45EC lea eax,[ebp-$14]
0041C40C BADCC44100 mov edx,$0041c4dc
0041C411 E8A6A2FEFF call @UStrLAsg
0041C416 8B1504E74100 mov edx,[$0041e704]
0041C41C 8B45EC mov eax,[ebp-$14]
0041C41F E870AFFFFF call StrToCurr
0041C424 DF7DE0 fistp qword ptr [ebp-$20]
0041C427 9B wait
0041C428 DF2DD83E4200 fild qword ptr [$00423ed8]
0041C42E DF6DE0 fild qword ptr [ebp-$20]
0041C431 DEC9 fmulp st(1)
0041C433 DF2DE03E4200 fild qword ptr [$00423ee0]
0041C439 DEC9 fmulp st(1)
0041C43B D835E4C44100 fdiv dword ptr [$0041c4e4]
0041C441 DF3DE83E4200 fistp qword ptr [$00423ee8]
0041C447 9B wait
以及 64 位:
Project3.dpr.13: currCalcValue := (currGross * (currPercent * StrToCurr('.01')));
0000000000428A0E 488D4D38 lea rcx,[rbp+$38]
0000000000428A12 488D1513010000 lea rdx,[rel $00000113]
0000000000428A19 E84213FEFF call @UStrLAsg
0000000000428A1E 488B4D38 mov rcx,[rbp+$38]
0000000000428A22 488B155F480000 mov rdx,[rel $0000485f]
0000000000428A29 E83280FFFF call StrToCurr
0000000000428A2E 4889C1 mov rcx,rax
0000000000428A31 488B0510E80000 mov rax,[rel $0000e810]
0000000000428A38 48F7E9 imul rcx
0000000000428A3B C7C110270000 mov ecx,$00002710
0000000000428A41 48F7F9 idiv rcx
0000000000428A44 488BC8 mov rcx,rax
0000000000428A47 488B0502E80000 mov rax,[rel $0000e802]
0000000000428A4E 48F7E9 imul rcx
0000000000428A51 C7C110270000 mov ecx,$00002710
0000000000428A57 48F7F9 idiv rcx
0000000000428A5A 488905F7E70000 mov [rel $0000e7f7],rax
请注意,32 位代码在 FPU 上执行算术,但 64 位代码使用整数算术执行该算术。这是关键的区别。
在32位代码中,执行以下计算:
- 将“0.01”转换为货币,即 100,允许 10,000 的定点偏移。
- 将 14,500 加载到 FPU 中。
- 乘以 100 得到 1,450,000。
- 乘以 11,824,200 得到 17,145,090,000,000。
- 除以 10,000^2 得到 171,450.9。
- 四舍五入到最接近的整数,得到 171,451。
- 将其存储在您的货币变量中。因此结果是 17.1451。
现在,在 64 位代码中,情况有些不同。因为我们一直使用64位整数。它看起来像这样:
- 将“0.01”转换为货币,即 100。
- 乘以 14,500,即 1,450,000。
- 除以 10,000,得到 145。
- 乘以 11,824,200 得到 1,714,509,000。
- 除以 10,000,即 171,450。呃哦,这里失去了精度。
- 将其存储在您的货币变量中。因此结果是 17.145。
因此,问题在于 64 位编译器在每个中间步骤都会除以 10,000。大概是为了避免溢出,64 位整数比浮点寄存器更有可能避免溢出。
如果是这样计算的话:
100 * 14,500 * 11,824,200 / 10,000 / 10,000
它会得到正确的答案。