flat assembler
Message board for the users of flat assembler.
Index
> Main > Float to string - strange results |
Author |
|
comrade 04 Mar 2009, 20:04
Some decimal numbers cannot be presented exactly in binary floating-point. See here. The Windows Calculator has special logic to correct for that.
|
|||
04 Mar 2009, 20:04 |
|
manfred 04 Mar 2009, 21:23
You probably misunderstood me. I said this function randomly prints correct value, or only first digits of integer and fractional part for same number in same executable. About 35% of program runs produces good results (eg. 666.999000...) and 65% gives only that two digits (6.9 in example with 666.999)...
|
|||
04 Mar 2009, 21:23 |
|
comrade 04 Mar 2009, 22:16
Ah, yes, I misread.
Can you factor out the int 80h syscall into putchar or something like that, so I can test this on Windows? I see you already have a putc, so what are those other int 80h for? |
|||
04 Mar 2009, 22:16 |
|
manfred 04 Mar 2009, 22:26
Int 80h with eax = 4 (sys_write) and ebx = 1 (stdout) is write_to_stdout(ecx = pointer to data, edx = length). I've implemented my own print function, but I can't use it here (in final code I will replace they by print calls, if I discover how can I pass pointer to string built on stack).
|
|||
04 Mar 2009, 22:26 |
|
revolution 04 Mar 2009, 23:01
Try inserting an finit at the start. Maybe the precision is not set by the OS before starting your app.
|
|||
04 Mar 2009, 23:01 |
|
comrade 04 Mar 2009, 23:22
Shouldn't you be cleaning up the stack after you call putc/int80h?
I refactored your program for Windows, seems to work fine: Code: ;########################################################################## ; printDouble ; 04.03.2008 ;########################################################################## format PE console 4.0 entry start ;########################################################################## _TITLE equ "printDouble" _NAME equ "printDouble" _VERSION equ "0.0" _VERSIONTEXT equ _VERSION ;########################################################################## include "%include%/win32am.inc" include "%include%/equates/kernel32.inc" include "%include%/equates/user32.inc" include "%include%/macro/if.inc" include "%include%/macro/macros.inc" OFFSET equ ;########################################################################## ;########################################################################## ;########################################################################## section ".code" code readable executable ;########################################################################## start: ;########################################################################## ;########################################################################## push ebx esi edi stdcall [GetStdHandle],STD_OUTPUT_HANDLE mov [hStdOut],eax stdcall printDouble,OFFSET wynik pop edi esi ebx stdcall [ExitProcess],0 ;########################################################################## printDouble: push ebp mov ebp, esp sub esp, 5112 digits equ ebp - 5112 fpustate equ ebp - 112 ten equ ebp - 4 temp equ ebp - 2 pushf push esi push ebx fsave [fpustate] xor esi, esi mov word [ten], 10 fnstcw [temp] or word [temp], (0Ch shl 8) ;rounding: cut fldcw [temp] mov eax, [ebp + 8] fld qword [eax] ;fpu registers: number ftst fstsw ax and ah, 01000101b jz .printDouble_ok cmp ah, 01000101b jnz .printDouble_check jmp .printDouble_error .printDouble_zero: push "0.0" mov eax, 4 mov ebx, 1 mov ecx, esp mov edx, 3 call int80h add esp,4 jmp .printDouble_end .printDouble_check: cmp ah, 01000000b jz .printDouble_zero cmp ah, 1 jnz .printDouble_error fchs push "-" call putc .printDouble_ok: fild word [ten] ;10, number fld st1 ;number, 10, number frndint ;integer part, 10, number fsub st2, st0 ;integer, 10, fractional align 16 .printDouble_div10: fxch st1 ;10, integer, fractional fld st1 ;integer, 10, integer, fractional fprem ;integer mod 10, 10, integer, fractional fistp word [digits + esi] ;10, integer, fractional fxch st1 ;integer, 10, fractional fdiv st0, st1 frndint ;integer(integer / 10), 10, fractional inc esi ftst fstsw ax sahf jnz .printDouble_div10 fstp st0 ;10, fractional fxch st1 ;fractional, 10 .printDouble_print_i: test esi, esi jz .printDouble_print_i_end dec esi mov al, [digits + esi] or al, "0" push eax call putc inc ch cmp ch, 80 jbe .printDouble_print_i .printDouble_print_i_end: push "." call putc xor ch, ch .printDouble_print_f: fmul st0, st1 ;fractional*10, 10 fist word [temp] fstsw ax and al, 18h jnz .printDouble_error mov al, [temp] or al, "0" push eax call putc inc ch fild word [temp] fsubp st1, st0 ftst fstsw ax sahf jz .printDouble_end cmp ch, 80 jae .printDouble_end jmp .printDouble_print_f .printDouble_error: push "r" push "Erro" mov eax, 4 mov ebx, 1 mov ecx, esp mov edx, 5 call int80h add esp,8 .printDouble_end: frstor [fpustate] pop ebx pop esi popf restore temp restore ten restore fpustate restore digits mov esp, ebp pop ebp ret 4 ;########################################################################## putc: lea eax,[esp+4] push eax ecx edx stdcall [WriteConsole],[hStdOut],eax,1,esp,0 pop edx ecx eax retn 4 ;########################################################################## int80h: cmp eax,4 ; sys_write jne .end cmp ebx,1 ; stdout jne .end push eax ecx edx stdcall [WriteConsole],[hStdOut],ecx,edx,esp,0 pop edx ecx eax .end: retn ;########################################################################## ;########################################################################## ;########################################################################## ;########################################################################## section ".data" data readable writeable data import library kernel32,"kernel32.dll",user32,"user32.dll" include "%include%/api/kernel32.inc" include "%include%/api/user32.inc" end data ;########################################################################## ;########################################################################## ; initialized data wynik dq 699.0 ;########################################################################## ; uninitialized data hStdOut dd ? argc dd ? argv rd 16 ;########################################################################## ;########################################################################## ;########################################################################## |
|||
04 Mar 2009, 23:22 |
|
manfred 05 Mar 2009, 06:52
No. Putc is my function and it's calling convention is stdcall. After syscalls I must only destroy string (ouch, I'm not doing it! base register, source index and flags content is destroyed!).
EDIT: Aarrgh! I forgot one fact - functions do not preserve ecx, but I used ch as counter in printing loops. Argh. Good code: Code: _printFloatingPoint: push ebp mov ebp, esp sub esp, 5112 digits equ ebp - 5112 fpustate equ ebp - 112 ten equ ebp - 4 temp equ ebp - 2 pushf push esi push ebx fsave [fpustate] xor esi, esi mov word [ten], 10 finit fnstcw [temp] or word [temp], (0Ch shl 8) ;rounding: cut fldcw [temp] cmp dword [ebp + 12], 64 ja ._printFloatingPoint_ld80 jb ._printFloatingPoint_ld32 mov eax, [ebp + 8] fld qword [eax] ;fpu registers: number jmp ._printFloatingPoint_start ._printFloatingPoint_ld80: mov eax, [ebp + 8] fld tword [eax] ;fpu registers: number jmp ._printFloatingPoint_start ._printFloatingPoint_ld32: mov eax, [ebp + 8] fld dword [eax] ;fpu registers: number ._printFloatingPoint_start: ftst fstsw ax and ah, 01000101b jz ._printFloatingPoint_ok cmp ah, 01000101b jnz ._printFloatingPoint_check jmp ._printFloatingPoint_error ._printFloatingPoint_zero: push "0.0" push 3 lea eax, [esp + 4] push eax call print add esp, 4 jmp ._printFloatingPoint_end ._printFloatingPoint_check: cmp ah, 01000000b jz ._printFloatingPoint_zero cmp ah, 1 jnz ._printFloatingPoint_error fchs push "-" call putc ._printFloatingPoint_ok: fild word [ten] ;10, number fld st1 ;number, 10, number frndint ;integer part, 10, number fsub st2, st0 ;integer, 10, fractional align 16 ._printFloatingPoint_div10: fxch st1 ;10, integer, fractional fld st1 ;integer, 10, integer, fractional fprem ;integer mod 10, 10, integer, fractional fistp word [digits + esi] ;10, integer, fractional fxch st1 ;integer, 10, fractional fdiv st0, st1 frndint ;integer(integer / 10), 10, fractional inc esi ftst fstsw ax sahf jnz ._printFloatingPoint_div10 fstp st0 ;10, fractional fxch st1 ;fractional, 10 xor bh, bh ._printFloatingPoint_print_i: test esi, esi jz ._printFloatingPoint_print_i_end dec esi mov al, [digits + esi] or al, "0" push eax call putc inc bh cmp bh, 80 jbe ._printFloatingPoint_print_i ._printFloatingPoint_print_i_end: push "." call putc xor bh, bh ._printFloatingPoint_print_f: fmul st0, st1 ;fractional*10, 10 fist word [temp] fstsw ax and al, 18h jnz ._printFloatingPoint_error mov al, [temp] or al, "0" push eax call putc inc bh fild word [temp] fsubp st1, st0 ftst fstsw ax sahf jz ._printFloatingPoint_end cmp bh, 21 jae ._printFloatingPoint_end jmp ._printFloatingPoint_print_f ._printFloatingPoint_error: push "r" push "Erro" push 5 lea eax, [esp + 4] push eax call print add esp, 8 ._printFloatingPoint_end: frstor [fpustate] pop ebx pop esi popf restore temp restore ten restore fpustate restore digits mov esp, ebp pop ebp ret 8 _________________ Sorry for my English... |
|||
05 Mar 2009, 06:52 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.