Hi ,
what data type is result of multiplication of: (Currency * Double) on
Win64 (and on Win32)?
c:=1115;
d:=100000000;
writeln(Round(c*d)); // gives -72967440737
32 bit version gives always 111500000000 as a result (and
floating point math should always have extended precision intermeiate
there) . But even with double intermediate result on 64 bit versions
there should not be any problems. 1.1150000000000000E+011 is well in
range of that type.
Let's look at disassembly on Win32:
---------------------------------------------------------
(FPU here uses "st registers" 80 bits wide)
test_curr_int64.lpr:77 c1:=1115;
00401EFC a178a14200 mov 0x42a178,%eax
00401F01 a320204300 mov %eax,0x432020
00401F06 a17ca14200 mov 0x42a17c,%eax
00401F0B a324204300 mov %eax,0x432024
test_curr_int64.lpr:78 d:=100000000;
00401F10 a180a14200 mov 0x42a180,%eax
00401F15 a330204300 mov %eax,0x432030
00401F1A a184a14200 mov 0x42a184,%eax
00401F1F a334204300 mov %eax,0x432034
test_curr_int64.lpr:79 i1:=Round(c1*d);
00401F24 dd0530204300 fldl 0x432030 //
st0:=100000000
00401F2A dc0d08a14200 fmull 0x42a108 //
st0:=1000000000000
00401F30 df2d20204300 fildll 0x432020 //
st0:=11150000, st1:=1000000000000
00401F36 dec9 fmulp %st,%st(1) //
st0:=1.115e+019
00401F38 df2d28a04200 fildll 0x42a028 //
st0:=10000, st1:=1.115e+019
00401F3E def9 fdivrp %st,%st(1) //
st0:=1115000000000000
00401F40 df2d28a04200 fildll 0x42a028 //
st0:=10000, st1:=1115000000000000
00401F46 def9 fdivrp %st,%st(1) //
st0:=111500000000
00401F48 df7df8 fistpll -0x8(%ebp)
00401F4B 9b fwait
00401F4C 8b45f8 mov -0x8(%ebp),%eax
00401F4F a340204300 mov %eax,0x432040
00401F54 8b45fc mov -0x4(%ebp),%eax
00401F57 a344204300 mov %eax,0x432044
And now on Win64:
---------------------------
test_curr_int64.lpr:77 c1:=1115;
0000000100001EAC 48c70569410400b022aa00 movq
$0xaa22b0,0x44169(%rip) # 0x100046020
test_curr_int64.lpr:78 d:=100000000;
0000000100001EB7 488b05f2f20200 mov 0x2f2f2(%rip),%rax
# 0x1000311b0 <_$TEST_CURR_INT64$_Ld16>
0000000100001EBE 4889056b410400 mov %rax,0x4416b(%rip)
# 0x100046030
test_curr_int64.lpr:79 i1:=Round(c1*d);
0000000100001EC5 f20f100563410400 movsd
0x44163(%rip),%xmm0 // 100000000
0000000100001ECD f20f590553f20200 mulsd
0x2f253(%rip),%xmm0 // 1000000000000
0000000100001ED5 f2480f2dc8 cvtsd2si
%xmm0,%rcx // 1000000000000
0000000100001EDA 488b053f410400 mov 0x4413f(%rip),%rax
// 11150000
0000000100001EE1 480fafc8 imul
%rax,%rcx // -7296744073709551616 <---OVERFLOW HERE
0000000100001EE5 48b84b598638d6c56d34 movabs $0x346dc5d63886594b,%rax
0000000100001EEF 48f7e9 imul %rcx
0000000100001EF2 48c1fa0b sar $0xb,%rdx
0000000100001EF6 48c1e93f shr $0x3f,%rcx
0000000100001EFA 4801ca add %rcx,%rdx
0000000100001EFD 4889d1 mov %rdx,%rcx
0000000100001F00 e8fb110000 callq 0x100003100
<SYSTEM_$$_ROUND$CURRENCY$$INT64>
0000000100001F05 48890534410400 mov %rax,0x44134(%rip)
# 0x100046040
If I understand correctly multipllication "imul" is performed as
multiplication of two currency values (int64)
(11150000 * 1000000000000 = 1115 * 10^16) which is over Max Int64 ...
So on Win64 there is currency (int64) intermediate ...
L.
_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel