flat assembler
Message board for the users of flat assembler.

Index > Windows > A good FTOA

Author
Thread Post new topic Reply to topic
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 03 Feb 2012, 12:31
Hey, iv spent the last few hours looking through Google and other topics here. I found found a few that work, but they all convert the number into scientific notation. EG. 0.003 would be 0.3E-2, and I am looking for a procedure that will give me the decimal representation of 0.003.

So, if you guys can point me in the right direction then you could save me a lot of headache,

Thanks.

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 03 Feb 2012, 12:31
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 03 Feb 2012, 14:35
NTDLL (which is loaded with every Windows binary) has sprintf function.
It is probably the best way. Call GetProcAddress first to get its entry point and then
just call it with C-calling convention: parameters reversed and caller (YOU) cleans up the stack.

I am not sure however, how is DOUBLE passed in this case -- you need to do it
in C code and then disassemble it to see how it is done.
I assume it is put on stack as 8 bytes, but not sure.
Try it with debugger and see how it works.

P.S. If I am not too busy today - I will post some code later...
Post 03 Feb 2012, 14:35
View user's profile Send private message Send e-mail Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 04 Feb 2012, 01:05
Yes, i use that function to convert integers into strings. But I tryed as you said, but I am not sure how to phase a float?

What do I put here? ------v

cinvoke wsprintf,String1,'%d',Float1
Post 04 Feb 2012, 01:05
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 04 Feb 2012, 05:07
I meant sprintf() from NTDLL.
Post 04 Feb 2012, 05:07
View user's profile Send private message Send e-mail Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 04 Feb 2012, 05:25
Why didnt this work?
Code:
        FLD1
        MOV [Integer1],4
        FIDIV [Integer1]
        FSTP [Float1]
        invoke GetProcAddress,<invoke GetModuleHandle,"ntdll.dll">,"sprintf"
        MOV [Integer1],EAX
        stdcall [Integer1],String1,"%f",[Float1]
        _writeStr String1    
Post 04 Feb 2012, 05:25
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 04 Feb 2012, 06:12
I just tried the same - no luck.
It outputs the garbage.

Take a look here:
http://www.website.masmforum.com/tutorials/fptute/fpuchap6.htm#fbstp

Using this you can easily convert the FPU value into string.
Or you can simply break the FPU value into INTEGER and FRACTIONAL PART and print first the integer part, then decimal dot '.' and then fractional part.

Of course, you need to multiply the fractional part first to your desired precision. For example, if you need 8 digits after the decimal dot - multiply it by 100,000,000. Just do not forget padding zeroes.

For example, if you have 45.00000789 and you multiply the fractional part by 100,000,000 - you'll get 789, so if you print it without padding you'll get: 45.789 which is wrong, so watch out for these zeroes.
Post 04 Feb 2012, 06:12
View user's profile Send private message Send e-mail Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 04 Feb 2012, 06:46
Lol, this one kind of works, it outputs 32.0000
Code:
        MOV [Integer1],3
        FILD [Integer1]
        FSTP [Float1]
        invoke sprintf,String1,"%f",0,[Float1]
    
Post 04 Feb 2012, 06:46
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 04 Feb 2012, 06:53
Ok, i figured it out. The variable holding your floating point value ("Float1") has to be a quad word
Code:
     cinvoke sprintf,String1,"%lf",0,dword[Float1+4] 
                               ^       ^          ^
    

I put carrots under the important parts

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 04 Feb 2012, 06:53
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 04 Feb 2012, 13:32
I see, but I think that will print only one DWORD part of a QWORD value.
Post 04 Feb 2012, 13:32
View user's profile Send private message Send e-mail Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 04 Feb 2012, 16:01
Visual Studio 2010 C++ compiler:
Code:
#include "stdafx.h"
#include <stdlib.h>

int _tmain(int argc, _TCHAR* argv[])
{
00041000  push        ebp  
00041001  mov         ebp,esp  
00041003  and         esp,0FFFFFFC0h  
00041006  sub         esp,13Ch  
0004100C  mov         eax,dword ptr [___security_cookie (43000h)]  
00041011  xor         eax,esp  
00041013  mov         dword ptr [esp+138h],eax  
0004101A  push        esi  
        double number64 =(double)rand()/(double)RAND_MAX;
0004101B  mov         esi,dword ptr [__imp__rand (420A8h)]  
00041021  call        esi  
00041023  mov         dword ptr [esp+2Ch],eax  
00041027  fild        dword ptr [esp+2Ch]  
0004102B  fdiv        qword ptr [__real@40dfffc000000000 (421B8h)]  
00041031  fstp        qword ptr [esp+30h]  
   float number32 = (float)rand()/(float)RAND_MAX;
00041035  call        esi  
00041037  mov         dword ptr [esp+2Ch],eax  
0004103B  fild        dword ptr [esp+2Ch]  
    char buff[256];

 printf("Gonna get the string now (Yeah, this string is only to force to compiler to finish the rand stuff instead of blending it into the sprintf call)\n");
0004103F  mov         esi,dword ptr [__imp__printf (420A0h)]  
00041045  push        offset string "Gonna get the string now (Yeah, "... (420F8h)  
0004104A  fdiv        qword ptr [__real@40dfffc000000000 (421B8h)]  
00041050  fstp        dword ptr [esp+30h]  
00041054  call        esi  

   sprintf(buff,"64-bit number: %lf; 32-bit number: %f\n", number64, number32);
00041056  fld         dword ptr [esp+30h]  
0004105A  sub         esp,0Ch  
0004105D  fstp        qword ptr [esp+8]  
00041061  fld         qword ptr [esp+40h]  
00041065  lea         eax,[esp+48h]  
00041069  fstp        qword ptr [esp]  
0004106C  push        offset string "64-bit number: %lf; 32-bit numbe"... (4218Ch)  
00041071  push        eax  
00041072  call        dword ptr [__imp__sprintf (4209Ch)]  

   printf("%s", buff);
00041078  lea         ecx,[esp+50h]  
0004107C  push        ecx  
0004107D  push        offset string "%s" (421B4h)  
00041082  call        esi  
       return 0;
}
00041084  mov         ecx,dword ptr [esp+15Ch]  
0004108B  add         esp,20h  
0004108E  pop         esi  
0004108F  xor         ecx,esp  
00041091  xor         eax,eax  
00041093  call        __security_check_cookie (4109Ch)  
00041098  mov         esp,ebp  
0004109A  pop         ebp  
0004109B  ret      
This means that you must always supply a 64-bit float. In your call you should replace 0 with dword [float1]. Also, if you are using the extended headers then you just do "cinvoke sprintf, String1, "%lf", double [Float1]"
Post 04 Feb 2012, 16:01
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 05 Feb 2012, 00:12
1. I tried exactly this "%lf" format with a double value. Does not work.
2. sprintf() from VS2010 is not the same as from NTDLL. Those are diff. functions.
Post 05 Feb 2012, 00:12
View user's profile Send private message Send e-mail Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 05 Feb 2012, 02:14
I get "f" as result when I use either "%f" or "%lf". To fix this, rather than using NTDLL's version (which looks as limited as wsprintf is for floating point values and perhaps its use is not so well documented), you could import from MSVCRT.DLL, which has been around for quite a lot of time (since Windows 98 at least).

Code:
include 'win32axp.inc'

proc start
local buff[256]:BYTE, pi:QWORD, one:QWORD

   invoke GetProcAddress, <invoke GetModuleHandle,"MSVCRT.dll">, "sprintf"
   finit
   fldpi
   fstp [pi]
   fld1
   fstp [one]

   ccall eax, addr buff, "pi: %lf; one: %lf", double[pi], double[one]

   invoke MessageBox, 0, addr buff, "test", 0

   invoke ExitProcess, 0
endp

.end start    
I don't know if sprintf is working with double precision or just single precision though.
Post 05 Feb 2012, 02:14
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 05 Feb 2012, 02:24
OK I found the format specifications: http://msdn.microsoft.com/en-us/library/aa246400%28v=vs.60%29.aspx

So, %lf is unnecessary (and perhaps it is working by miracle), use %f instead.
Post 05 Feb 2012, 02:24
View user's profile Send private message Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 05 Feb 2012, 17:13
%g works better. This is because if you want it to convert 1.3, it will give you 1.3000000, but %g will truncate all of the zeros
Post 05 Feb 2012, 17:13
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
avcaballero



Joined: 02 Feb 2004
Posts: 212
Location: Madrid - Spain
avcaballero 09 Feb 2012, 15:58
I don't know if I'm late, but here my version goes.

You only need definitions:

http://www.abreojosensamblador.net/Productos/AOE/html/Pags_en/Chap01.html#Reales

Then, start writing code.

I have proved some numbers, I hope it works... sorry if not, I didn't have much time to did it. BTW, it is DOS based.

Quote:

D:\Alfonso\AVCH\TET>RealCF01
305.6250000
D:\Alfonso\AVCH\TET>RealCF01
.0004998
D:\Alfonso\AVCH\TET>RealCF01
.0049995
D:\Alfonso\AVCH\TET>RealCF01
.0499996
D:\Alfonso\AVCH\TET>RealCF01
.0349995
D:\Alfonso\AVCH\TET>RealCF01
.9349996
D:\Alfonso\AVCH\TET>RealCF01
10.9349992
D:\Alfonso\AVCH\TET>RealCF01
150.9349973
D:\Alfonso\AVCH\TET>RealCF01
150.0009153
D:\Alfonso\AVCH\TET>RealCF01
.0000146


Regards


Description:
Download
Filename: RealCF01.zip
Filesize: 2.84 KB
Downloaded: 305 Time(s)


_________________
Siempre aprendiendo
Post 09 Feb 2012, 15:58
View user's profile Send private message Visit poster's website Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 10 Feb 2012, 03:13
Wow, that is pretty cool, but I was hoping for a windows based one. anyway i figured it out, but thanks for the effort and work you put into this
Post 10 Feb 2012, 03:13
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.