------------------------------------------------------------ [BUG/PRB.] VFP 9.0 FIX - ROUND() Function January 2023 ------------------------------------------------------------ CCB 1. BUG: There is a test program from Mr. Christof Wollenhaupt: *PROC testroundfunction ?ROUND(512.9250000000,2) && Displays 512.92 ?ROUND(512.925000000,2) && Displays 512.93 WAIT RETURN * END OF PROC TESTROUNDFUNCTION. We think they will display 512.93, but: ?ROUND(512.9250000000,2) && Displays 512.92 2. CAUSE: Please refer to the head of the testroundfunction.fxp: 00000000: FE F2 FF 22-02 01 00 00-00 D8 00 00-00 A1 00 00 00000010: 00 37 00 00-00 00 00 00-00 00 00 00-00 00 00 00 00000020: 00 00 00 00-00 00 00 3F-27 00 00 00-00 25 00 00 00000030: 00 00 00 00-00 00 00 00-00 68 00 00-00 03 00 00 00000040: 00 62 00 00-00 8F 56 82-47 1C 00 00-00 85 00 00 00000050: 35 00 00 00-19 00 02 F8-03 01 FC 43-FA 0E 0A 66 00000060: 66 66 66 66-07 80 40 F8-01 02 54 FD-FE 19 00 02 00000070: F8 03 01 FC-43 FA 0D 09-66 66 66 66-66 07 80 40 00000080: F8 01 02 54-FD FE 03 00-55 00 00 91-01 91 01 31 00000090: 00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00 the compiled p-code for the statement "?ROUND(512.9250000000,2)" from 0x00000054: 19 00 02 F8 03 01 FC 43 FA 0E 0A 66 66 66 66 66 07 80 40 F8 01 02 54 FD FE -------------------------------------------------------------------------- The width of the floating-point number is 0x0E (dec: 14). The number of decimal places is 0x0A (dec: 10). The 64-bit floating-point number is 0x4080076666666666. the compiled p-code for the statement "?ROUND(512.925000000,2)" from 0x0000006D: 19 00 02 F8 03 01 FC 43 FA 0D 09 66 66 66 66 66 07 80 40 F8 01 02 54 FD FE -------------------------------------------------------------------------- The width of the floating-point number is 0x0D (dec: 13). The number of decimal places is 0x09 (dec: 9). The 64-bit floating-point number is 0x4080076666666666. They are the same 64-bit floating-point numbers: 512.9250000000 = 0x4080076666666666 512.925000000 = 0x4080076666666666 the difference is the width of the floating-point number and the number of decimal places. For the details when VFP calculates ROUND(512.9250000000,2): 512. 9249 9999 9999 9546 0 + 0. 0000 0000 0000 0500 0 (n=10, eps = 0.5*10^(-(n+3)) = 5.0000000000000001520E-14) ---------------------------- 512. 9249 9999 9999 9546 0 512. 9249 9999 9999 9546 0 * 100. 0000 0000 0000 0000 0 ---------------------------- 51292. 4999 9999 9992 720 + 0. 5000 0000 0000 0000 0 ---------------------------- 51292. 9999 9999 9992 720 floor(51292. 9999 9999 9992 720) = 51292.000000000000000 51292. 0000 0000 0000 0000 0 / 100. 0000 0000 0000 0000 0 ---------------------------- 512. 9199 9999 9999 9590 0 + 0. 0000 0500 0000 0000 0 (n=2, eps = 0.5*10^(-(n+3)) = 5.0000000000000004090E-06) ---------------------------- 512. 9200 0499 9999 9464 0 So ROUND(512.9250000000,2) = 512.92. For the details when VFP calculates ROUND(512.925000000,2): 512. 9249 9999 9999 9546 0 + 0. 0000 0000 0000 4999 9 (n=9, eps = 0.5*10^(-(n+3)) = 4.9999999999999999000E-13) ---------------------------- 512. 9250 0000 0000 4092 0 512. 9250 0000 0000 4092 0 * 100. 0000 0000 0000 0000 0 ---------------------------- 51292. 5000 0000 0043 660 + 0. 5000 0000 0000 0000 0 ---------------------------- 51293. 0000 0000 0043 660 floor(51293. 0000 0000 0043 660) = 51293.000000000000000 51293. 0000 0000 0000 0000 0 / 100. 0000 0000 0000 0000 0 ---------------------------- 512. 9299 9999 9999 9500 0 + 0. 0000 0500 0000 0000 0 (n=2, eps = 0.5*10^(-(n+3)) = 5.0000000000000004090E-06) ---------------------------- 512. 9300 0499 9999 9374 0 So ROUND(512.925000000,2) = 512.93. If we enable adjusting the precision of the floating-point numbers in Visual FoxPro Advanced, Visual FoxPro Advanced will set 15 valid digits for the following functions: ROUND() Function, INT() Function. Visual FoxPro Advanced will adjust the floating-point numbers before call the floor() function: 51292. 9999 9999 9992 720 +00000. 0000 0000 005 -------------------------- 51293. 0000 0000 0042 720 floor(51292. 9999 9999 9992 720 +00000. 0000 0000 005) = 51293.000000000000000 So ROUND(512.9250000000,2) = 512.93. 51293. 0000 0000 0043 660 +00000. 0000 0000 005 -------------------------- 51293. 0000 0000 0093 660 floor(51293. 0000 0000 0043 660 +00000. 0000 0000 005) = 51293.000000000000000 So ROUND(512.925000000,2) = 512.93. Visual FoxPro Advanced will also set 15 valid digits and round the value to integer when subtract two datetimes to get the difference between them in seconds. For the test program from Mr. Sergey Karimov: lnsec= {^2000/01/01 01:01:00 AM}-{^2000/01/01 00:00:00 AM} a1= lnsec%3600 a2= a1/60 ?lnsec, a1, a2, FLOOR(a1)/60, FLOOR(a1/60) Now it can run fine if we enable adjusting the precision of the floating-point numbers in Visual FoxPro Advanced. 3. RESOLUTION: We can write some code to fix the BUG. Label4aea26 :: mov eax , dword ptr [ esp + 20 ] ;0x004aea26 : 8b442414 fld qword ptr [ 8 * ebp + offset Data922520 ] ;0x004aea2a : dd04ed20259200 sub esp , 08h ;0x004aea31 : 83ec08 fstp qword ptr [ esp + 40 ] ;0x004aea34 : dd5c2428 test eax , eax ;0x004aea38 : 85c0 jne Label591da6 ;0x004aea3a : 0f8566330e00 fld qword ptr [ esp + 40 ] ;0x004aea40 : dd442428 fmul st(0) , st(1) ;0x004aea44 : d8c9 ; ; ------------------------------------------------- ; VFP 9.0 FIX - ROUND() Function ; February 2017 ; ------------------------------------------------- ; CCB ; ; Sometimes the ROUND() function returns wrong result, for example, ; ?ROUND(512.9250000000,2) && Displays 512.92 ; ?ROUND(512.925000000,2) && Displays 512.93 ; ; 2017/2/26, by ccb ; cmp dword ptr vfpa_sys9001_data,00h je Label4aea46 fld st(0) fabs fldlg2 fxch st(1) fyl2x fld st(0) fistp dword ptr [ esp ] mov ecx,dword ptr [ esp ] cmp ecx,80000000h je Label4aea45 and ecx,80000000h test ecx,ecx jne Label4aea45 mov eax,0 fadd qword ptr [ 8 * eax + offset Data922438 ] mov eax,10 fadd qword ptr [ 8 * eax + offset Data922438 ] fistp dword ptr [ esp ] mov eax,15 sub eax,dword ptr [ esp ] cmp eax,0 jle Label4aea46 cmp eax,15 jge Label4aea46 fld st(0) fistp dword ptr [ esp ] mov ecx,dword ptr [ esp ] cmp ecx,80000000h je Label4aea46 and ecx,80000000h test ecx,ecx jne Label4aea44 fadd qword ptr [ 8 * eax + offset Data922438 ] jmp Label4aea46 Label4aea44 :: fsub qword ptr [ 8 * eax + offset Data922438 ] jmp Label4aea46 Label4aea45 :: fstp st(0) jmp Label4aea46 Label4aea46 :: fadd qword ptr [ Data9256b0 ] ;0x004aea46 : dc05b0569200 fstp qword ptr [ esp ] ;0x004aea4c : dd1c24 fstp st(0) ;0x004aea4f : ddd8 call floor ;0x004aea51 : ff15a0799100 fdiv qword ptr [ esp + 40 ] ;0x004aea57 : dc742428 Label4aea5b :: add esp , 08h ;0x004aea5b : 83c408 test ebx , ebx ;0x004aea5e : 85db jne Label591dc2 ;0x004aea60 : 0f855c330e00 Label4aea66 :: mov eax , dword ptr [ esp + 24 ] ;0x004aea66 : 8b442418 fstp qword ptr [edi] ;0x004aea6a : dd1f test eax , eax ;0x004aea6c : 85c0 jne Label591dc9 ;0x004aea6e : 0f8555330e00 mov eax , dword ptr [ esp + 20 ] ;0x004aea74 : 8b442414 test eax , eax ;0x004aea78 : 85c0 jne Label591e1c ;0x004aea7a : 0f859c330e00 mov eax , dword ptr [ esi + 8 ] ;0x004aea80 : 8b4608 cmp ebp , eax ;0x004aea83 : 3be8 ja Label591e28 ;0x004aea85 : 0f879d330e00 Label4aea8b :: cmp ebp , 012h ;0x004aea8b : 83fd12 jnl Label591e42 ;0x004aea8e : 0f8dae330e00 Label4aea94 :: mov dword ptr [ esi + 8 ] , ebp ;0x004aea94 : 896e08 Label4aea97 :: mov eax , dword ptr [ esi + 4 ] ;0x004aea97 : 8b4604 cmp eax , 028h ;0x004aea9a : 83f828 jnl Label4aeaa3 ;0x004aea9d : 7d04 inc eax ;0x004aea9f : 40 mov dword ptr [ esi + 4 ] , eax ;0x004aeaa0 : 894604 Label4aeaa3 :: mov eax , dword ptr [ esp + 28 ] ;0x004aeaa3 : 8b44241c test eax , eax ;0x004aeaa7 : 85c0 jne Label591e4c ;0x004aeaa9 : 0f859d330e00 Label4aeaaf :: pop edi ;0x004aeaaf : 5f pop esi ;0x004aeab0 : 5e pop ebp ;0x004aeab1 : 5d pop ebx ;0x004aeab2 : 5b mov esp , ebp ;0x004aeab3 : 8be5 pop ebp ;0x004aeab5 : 5d ret ;0x004aeab6 : c3 4. APPLIES TO: VFP 6.0.8167.0 VFP 6.0.8961.0 (SP5) VFP 7.0.0.9262 VFP 7.0.0.9465 (SP1) VFP 8.0.0.2521 VFP 8.0.0.3117 (SP1) VFP 9.0.0.2412 VFP 9.0.0.3504 (SP1) VFP 9.0.0.4611 (SP2) VFP 9.0.0.5015 (SP2) VFP 9.0.0.5411 (SP2) VFP 9.0.0.5721 (SP2) VFP 9.0.0.5815 (SP2) VFP 9.0.0.6303 (SP2) VFP 9.0.0.6602 (SP2) VFP 9.0.0.7423 (SP2) The bug has been fixed in VFP Advanced. 5. REFERENCE WEBSITES: 1, baiyujia.com: http://www.baiyujia.com http://www.baiyujia.com/vfpdocuments/f_vfp9fix23.asp http://www.baiyujia.com/vfpdocuments/f_vfp9fix97.asp http://www.baiyujia.com/vfpdocuments/f_vfp9fix98.asp http://www.baiyujia.com/vfpdocuments/f_vfp9fix123.asp http://www.baiyujia.com/vfpdocuments/f_vfp9fix124.asp 2, microsoft.com: https://social.msdn.microsoft.com/Forums/en-US/cee551be-35f8-4ddc-a07e-51d2d7f79345/rounding-bug-in-vfp8 https://social.msdn.microsoft.com/Forums/en-US/a8725753-5815-4d45-aa7b-bdead9277986/how-can-i-subract-datetime-values 3, foxite.com: https://www.foxite.com/archives/round-problem-0000070917.htm https://www.foxite.com/archives/interesting-behavior-of-inputmask-0000406050.htm https://www.foxite.com/archives/round-0000223089.htm https://www.foxite.com/archives/how-to-compute-the-elapsed-time-in-foxpro-0000058524.htm https://www.foxite.com/archives/int-strange-behavior-0000445268.htm 4, tek-tips.com: http://www.tek-tips.com/viewthread.cfm?qid=531793 http://www.tek-tips.com/viewthread.cfm?qid=1738764 5, foxpert.com: http://www.foxpert.com/foxpro/knowlbits/files/knowlbits_201102_1.html 6, fox-id.org: http://www.fox-id.org/smf/general-code-activex-com/hasil-perhitungan-vfp-kok-beda-sama-kalkulator/ 6. OTHER: For reference only, there is no guarantees. Any questions or suggestions, please send me an email at ccb2000@163.com. |