我们最近开始创建64位构建我们的应用程序的过程.在比较测试中,我们发现64位版本的计算方式不同.我有一个代码示例来演示两个构建之间的区别.
var currPercent,currGross,currCalcValue : Currency; begin currGross := 1182.42; currPercent := 1.45; currCalcValue := (currGross * (currPercent * StrToCurr('.01'))); ShowMessage(CurrToStr(currCalcValue)); end;
如果您在32位版本中执行此操作,则currCalcValue将使用17.1451计算,而64位版本则以17.145返回.
为什么64位版本不计算出额外的小数位?所有变量都定义为4个十进制货币值.
解决方法
这是我的SSCCE基于你的代码.请注意使用控制台应用程序.使生活更简单.
{$APPTYPE CONSOLE} uses SysUtils; var currPercent,currCalcValue : Currency; begin currGross := 1182.42; currPercent := 1.45; currCalcValue := (currGross * (currPercent * StrToCurr('.01'))); Writeln(CurrToStr(currCalcValue)); Readln; end.
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,000.
>除以10,这是145.
>乘以11,200给1,714,509,这是171,450.呃哦,在这里丢了精度.
>将其存储在您的货币变量中.结果是17.145.
所以问题是64位编译器在每一个中间步骤中都会划分10,000.大概是为了避免溢出,比浮点寄存器更有可能在64位整数.
如何做这样的计算:
100 * 14,500 * 11,200 / 10,000 / 10,000
它会得到正确的答案.