------------------------------------------------------------------------------------------------
[BUG/PRB.] ADJUST THE PRECISION OF THE FLOATING-POINT NUMBERS FOR THE ROUND() FUNCTION
January 2025
------------------------------------------------------------------------------------------------
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.
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.
Label4ae942 ::
push ebp ;0x004ae942 : 55
mov ebp , esp ;0x004ae943 : 8bec
and esp , 0FFFFFFF8h ;0x004ae945 : 83e4f8
sub esp , 018h ;0x004ae948 : 83ec18
push ebx ;0x004ae94b : 53
push ebp ;0x004ae94c : 55
push esi ;0x004ae94d : 56
push edi ;0x004ae94e : 57
mov dword ptr [ esp + 20 ] , 00h ;0x004ae94f : c744241400000000
call Fun420d8c ;0x004ae957 : e83024f7ff
mov esi , eax ;0x004ae95c : 8bf0
lea ebx , dword ptr [ esi + 44 ] ;0x004ae95e : 8d5e2c
push ebx ;0x004ae961 : 53
lea edi , dword ptr [ esp + 32 ] ;0x004ae962 : 8d7c2420
call Fun420dd3 ;0x004ae966 : e86824f7ff
test eax , eax ;0x004ae96b : 85c0
jne Label4aeaaf ;0x004ae96d : 0f853c010000
mov edi , ebx ;0x004ae973 : 8bfb
call Fun529a6e ;0x004ae975 : e8f4b00700
cmp byte ptr [ebx] , 049h ;0x004ae97a : 803b49
mov ebp , dword ptr [ ebx + 12 ] ;0x004ae97d : 8b6b0c
mov edi , 0385h ;0x004ae980 : bf85030000
jne Label591cc0 ;0x004ae985 : 0f8535330e00
Label4ae98b ::
mov al , byte ptr [esi] ;0x004ae98b : 8a06
xor ecx , ecx ;0x004ae98d : 33c9
cmp al , 059h ;0x004ae98f : 3c59
sete cl ;0x004ae991 : 0f94c1
test ecx , ecx ;0x004ae994 : 85c9
mov dword ptr [ esp + 24 ] , ecx ;0x004ae996 : 894c2418
jne Label591ce8 ;0x004ae99a : 0f8548330e00
Label4ae9a0 ::
cmp al , 049h ;0x004ae9a0 : 3c49
je Label591cf6 ;0x004ae9a2 : 0f844e330e00
cmp al , 059h ;0x004ae9a8 : 3c59
je Label591d0b ;0x004ae9aa : 0f845b330e00
cmp al , 04Eh ;0x004ae9b0 : 3c4e
jne Label591d26 ;0x004ae9b2 : 0f856e330e00
Label4ae9b8 ::
test ebp , ebp ;0x004ae9b8 : 85ed
jl Label591d4e ;0x004ae9ba : 0f8c8e330e00
mov eax , dword ptr [ esi + 8 ] ;0x004ae9c0 : 8b4608
cmp eax , ebp ;0x004ae9c3 : 3bc5
mov ecx , eax ;0x004ae9c5 : 8bc8
jle Label591d60 ;0x004ae9c7 : 0f8e93330e00
Label4ae9cd ::
cmp ecx , 012h ;0x004ae9cd : 83f912
jnl Label591d6e ;0x004ae9d0 : 0f8d98330e00
cmp eax , ebp ;0x004ae9d6 : 3bc5
jle Label591d67 ;0x004ae9d8 : 0f8e89330e00
mov edx , eax ;0x004ae9de : 8bd0
Label4ae9e0 ::
cmp ebp , 012h ;0x004ae9e0 : 83fd12
jg Label591d78 ;0x004ae9e3 : 0f8f8f330e00
Label4ae9e9 ::
mov ax , word ptr [ esi + 22 ] ;0x004ae9e9 : 668b4616
test ax , ax ;0x004ae9ed : 6685c0
lea edi , dword ptr [ esi + 16 ] ;0x004ae9f0 : 8d7e10
je Label477a2f ;0x004ae9f3 : 0f843690fcff
test ah , ah ;0x004ae9f9 : 84e4
js Label591d82 ;0x004ae9fb : 0f8881330e00
mov eax , 01h ;0x004aea01 : b801000000
Label4aea06 ::
xor ebx , ebx ;0x004aea06 : 33db
test eax , eax ;0x004aea08 : 85c0
mov eax , dword ptr [ esp + 24 ] ;0x004aea0a : 8b442418
setl bl ;0x004aea0e : 0f9cc3
test eax , eax ;0x004aea11 : 85c0
jne Label4aea1c ;0x004aea13 : 7507
mov ecx , edi ;0x004aea15 : 8bcf
call Fun53e46a ;0x004aea17 : e84efa0800
Label4aea1c ::
test ebx , ebx ;0x004aea1c : 85db
fld qword ptr [edi] ;0x004aea1e : dd07
jne Label591d9f ;0x004aea20 : 0f8579330e00
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 - ADJUST THE PRECISION OF THE FLOATING-POINT NUMBERS FOR THE 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
IFDEF RAX
push esi
lea esi , dword ptr [ Data922438 ]
fadd qword ptr [ 8 * eax + esi ]
pop esi
ELSE
fadd qword ptr [ 8 * eax + offset Data922438 ]
ENDIF
mov eax,0Ah
IFDEF RAX
push esi
lea esi , dword ptr [ Data922438 ]
fadd qword ptr [ 8 * eax + esi ]
pop esi
ELSE
fadd qword ptr [ 8 * eax + offset Data922438 ]
ENDIF
fistp dword ptr [ esp ]
mov eax,0Fh
sub eax,dword ptr [ esp ]
cmp eax,0
jl Label4aea46
cmp eax,0Fh
jg 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
IFDEF RAX
push esi
lea esi , dword ptr [ Data922438 ]
fadd qword ptr [ 8 * eax + esi ]
pop esi
ELSE
fadd qword ptr [ 8 * eax + offset Data922438 ]
ENDIF
jmp Label4aea46
Label4aea44 ::
IFDEF RAX
push esi
lea esi , dword ptr [ Data922438 ]
fsub qword ptr [ 8 * eax + esi ]
pop esi
ELSE
fsub qword ptr [ 8 * eax + offset Data922438 ]
ENDIF
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_vfp9fix37.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix38.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
http://www.baiyujia.com/vfpdocuments/f_vfp9fix255.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix256.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix257.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix258.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix259.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix260.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix303.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix304.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix305.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix306.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix373.asp
http://www.baiyujia.com/vfpdocuments/f_vfp9fix374.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.
|