The MASM Forum

General => The Campus => Topic started by: Chris. on August 16, 2017, 03:40:24 AM

Title: Printing floating point not working.
Post by: Chris. on August 16, 2017, 03:40:24 AM
Code: [Select]
.386
.model flat, stdcall
option casemap :none 

includelib \masm32\lib\msvcrt.lib
sprintf proto C :vararg
includelib \masm32\lib\user32.lib
MessageBoxA proto :ptr,:ptr,:ptr,:DWORD
includelib \masm32\lib\kernel32.lib
ExitProcess proto :dword

.data
   format db "%fl", 13, 10, 0
   _title db "Result",13,10,0
   Aval REAL10 14.000
   Bval REAL10 2.000
   Cval REAL10 19.000
   _fourval REAL8 4.000
   $interm dword "%fl",13,10,0
   $results dword "%fl"



.code
main PROC
LOCAL szBuf[9]:byte



fld Bval ;  [loads first instance of b]
fld Bval ;  [loads second instance of b]
fmulp ; [b*b = b^2]
fld Aval ;[Load a (a*c)]
fld Cval ;[Load c (a*c)]
fmulp ;(a*c)
fmul _fourval ;[4*a*c]
fsubp;[b^2-4*(a)*(c)]
ftst ;compare ST(0) with 0.0
fstsw ax ;[store camparison results in ax]
fwait;wait
sahf ;store flags in AH register
jnz _negative ;jump if
fsqrt
jmp Finished



_negative:
fchs
fsqrt
xor eax,eax
fist $interm
mov eax, $interm






Finished: 
   invoke sprintf, addr szBuf, offset $interm, eax
   invoke MessageBoxA, 0, addr szBuf, offset _title, 0
   invoke ExitProcess, 0


main ENDP
END main

I used the "fist"command to store the floating point in $interm var.
I move the $interm var into eax and try to print the eax value as a floating point.
When I test it it displays !
Is my code wrong?
Can you print directly from FPU registers?
Title: Re: Printing floating point not working.
Post by: aw27 on August 16, 2017, 04:19:50 AM
I don't understand this;
$interm dword "%fl",13,10,0

then:
fist $interm
Title: Re: Printing floating point not working.
Post by: Chris. on August 16, 2017, 04:44:32 AM
I thought the "fist" instruction allows you to store fpu numbers into memory or variables.
http://www.ray.masmcode.com/tutorial/fpuchap5.htm#fist (http://www.ray.masmcode.com/tutorial/fpuchap5.htm#fist)


The $interm dword "%fl",13,10,0 was just me trying out different things as real4 real8 and real10 did not work.

1) REAL4 gives - 1>Arraytest.asm(19): error A2187: must use floating-point initializer

2) REAL8 gives 1>Arraytest.asm(53): error A2022: instruction operands must be the same size
                       1>Arraytest.asm(19): error A2187: must use floating-point initializer

3) REAL10 gives 1>Arraytest.asm(53): error A2022: instruction operands must be the same size
                        1>Arraytest.asm(19): error A2187: must use floating-point initializer

Title: Re: Printing floating point not working.
Post by: jj2007 on August 16, 2017, 04:55:35 AM
Can you print directly from FPU registers?

Yes, but that would require MasmBasic ( e.g.: Print Str$(ST(5)) ). Your problem is elsewhere; try this:

Code: [Select]
Finished:
.if 0
  txFormat db "%3f", 13, 10, 0
  test8 REAL8 123.456
.endif
   invoke sprintf, addr szBuf, offset txFormat, test8
   invoke MessageBoxA, 0, addr szBuf, offset _title, 0
   invoke ExitProcess, 0

More specifically,
Code: [Select]
$interm dword "%fl",13,10,0
fist $interm

will definitely not do what you want. Check what kind of float parameter is expected by sprintf. Hint: It's neither a DWORD nor a REAL4; and fist is the wrong instruction for a float.

And a general advice: Don't guess. Read the help files and MSDN carefully, and try to understand them. Code step by step, for example: define a number and see if you can print it:
Code: [Select]
.data
mydouble REAL8 12345.6789012345
myformat db "This is a real8: %f", 13, 0
.code
printf proto C :vararg
invoke printf, addr myformat, mydouble

The thrilling learning step is to find the right instruction from the fist family that will transfer a value from the FPU to mydouble.

And all that would be much simpler and clearer with include \masm32\include\masm32rt.inc instead of all the crappy includes on top.
Title: Re: Printing floating point not working.
Post by: aw27 on August 16, 2017, 04:58:56 AM
This does not produce errors. You will have to check what is different from yours:

Code: [Select]
.386
.model flat, stdcall
option casemap :none 

includelib \masm32\lib\msvcrt.lib
sprintf proto C :vararg
includelib \masm32\lib\user32.lib
MessageBoxA proto :ptr,:ptr,:ptr,:DWORD
includelib \masm32\lib\kernel32.lib
ExitProcess proto :dword

.data
   format db "%fl", 13, 10, 0
   _title db "Result",13,10,0
   Aval REAL10 14.000
   Bval REAL10 2.000
   Cval REAL10 19.000
   _fourval REAL8 4.000
   value dq ?
   $interm db "%lf",13,10,0
   $results dword "%fl"



.code
main PROC
LOCAL szBuf[9]:byte



fld Bval ;  [loads first instance of b]
fld Bval ;  [loads second instance of b]
fmulp ; [b*b = b^2]
fld Aval ;[Load a (a*c)]
fld Cval ;[Load c (a*c)]
fmulp ;(a*c)
fmul _fourval ;[4*a*c]
fsubp;[b^2-4*(a)*(c)]
ftst ;compare ST(0) with 0.0
fstsw ax ;[store camparison results in ax]
fwait;wait
sahf ;store flags in AH register
jnz _negative ;jump if
fsqrt
jmp Finished



_negative:
fchs
fsqrt
xor eax,eax
fstp value
mov eax, dword ptr value
mov edx, dword ptr [value+4]


Finished: 
   invoke sprintf, addr szBuf, offset $interm, eax, edx
   invoke MessageBoxA, 0, addr szBuf, offset _title, 0
   invoke ExitProcess, 0


main ENDP
END main
Title: Re: Printing floating point not working.
Post by: Chris. on August 17, 2017, 03:31:24 AM
Ok thanks,  I read this guide: (http://www.website.masmforum.com/tutorials/fptute/index.html (http://www.website.masmforum.com/tutorials/fptute/index.html)) and although it has helped a lot it didn't mention the "fstp" instruction.

My question is about this line "mov edx, dword ptr [value+4]"  I am aware that it is an offset. For example if i used "mov ah, [var+3]" with a variable like  "var db 2,4,6,8,10" it would place the number 8 into the ah register because the  array is "var db 2(0),4(1),6(2),8(3),10(4)"

Is the same applied to this situation in terms of memory address?
Title: Re: Printing floating point not working.
Post by: jj2007 on August 17, 2017, 03:52:38 AM
For example if i used "mov eax, [var+3]" with a variable like  "var db 2,4,6,8,10" it would place the number 8 into the eax register

I don't think so, but if I had the full code, I would place an int 3 in front of the mov and launch Olly. Why do you speculate and guess, instead of looking yourself what's going on?
Title: Re: Printing floating point not working.
Post by: Chris. on August 17, 2017, 04:42:15 AM
I made a error that I will fix, but my question was trying to understand how mov edx, dword ptr [value+4] affects code.

Keep in mind that I use Visual Studio debugger and I am learning x86 as my "first" programming language.

When you say olly I had no idea what you meant at first.

Are you implying olly debugger gives more details(or is better) than Visual Studios debugger?
Title: Re: Printing floating point not working.
Post by: aw27 on August 17, 2017, 04:51:56 AM
It is like this:

The value is saved to a REAL8/qword/8 bytes with this instruction fstp value.

To print it you need to use 2 general purpose registers because one only takes 1 dword.
So, one GPR takes the lower part of the qword, the other the higher part.

If you don't like this way, you can also proceed like this:
invoke sprintf, addr szBuf, offset $interm, value
Title: Re: Printing floating point not working.
Post by: jj2007 on August 17, 2017, 04:56:26 AM
Are you implying olly debugger gives more details(or is better) than Visual Studios debugger?

No idea. VS is so slow that I refuse to open it. I use Olly from RM. (http://masm32.com/board/index.php?topic=5314.msg63302#msg63302)
Title: Re: Printing floating point not working.
Post by: nidud on August 17, 2017, 05:52:19 AM
Difficult to find any better debugger than VC for 32-bit I think. VC6 still works out-of-the-box. Fast with full symbolic info. Watches, Variables, Stack, and Register windows spans over multiple screens (a must) and so on.

The newer versions are as you say, slow, and the old version lack support for xmm registers but it's difficult to compare olly to the above thought.
Title: Re: Printing floating point not working.
Post by: habran on August 17, 2017, 06:21:33 AM
I use Microsoft Visual Studio Community 2013, with added SDE debugger for all my work. You can switch between Local Windows Debugger and SDE debugger
It can work at the same time with C and asm source, it can debug both at the same time and it can debug and run in debug mode EVEX instructions as well, it understand RIP register as well.
It is at the same time a pretty good text editor with intel and syntax highlighting, you can download from the Terraspace extended Visual Studio Syntax Highlighting (http://www.terraspace.co.uk/uasm.html) 
Title: Re: Printing floating point not working.
Post by: Chris. on August 17, 2017, 03:55:28 PM
I have another question about printing.

The code below takes the value of var1 and var2 and prints it in edx:eax according to the format.
What if i want two different variables in one string?

The ("$interm db "%0.4f(squareroot)","+","%0.4f(squareroot2)",13,10,0") inst meant to be real, its just a way to show the format I am trying to achieve

Code: [Select]
.386
.model flat, stdcall
option casemap :none 

includelib \masm32\lib\msvcrt.lib
sprintf proto C :vararg
includelib \masm32\lib\user32.lib
MessageBoxA proto :ptr,:ptr,:ptr,:DWORD
includelib \masm32\lib\kernel32.lib
ExitProcess proto :dword

.data
   _title db "Result",13,10,0
   $interm db "%0.4f","+","%0.4f",13,10,0
   Aval REAL10 1.000
   Bval REAL10 -2.000
   Cval REAL10 19.000
   _fourval REAL8 4.000
   squareroot dq ?
   squareroot2 dq ?
 

.code
main PROC
LOCAL szBuf[9]:byte



fld Bval ;  [loads first instance of b]
fld Bval ;  [loads second instance of b]
fmulp  ; [b*b = b^2]
fld Aval ;[Load a (a*c)]
fld Cval ;[Load c (a*c)]
fmulp ;(a*c)
fmul _fourval ;[4*a*c]
fsubp;[b^2-4*a*c]
ftst ;compare ST(0) with 0.0

fstsw ax ;[store camparison results in ax]
fwait;wait
sahf ;transfer flags from AH register
jb _negative ;jump if <0
fsqrt ;sqrt(b^2-4*a*c)
jmp Finished



_negative:
fchs
fsqrt



Finished: 

   fstp squareroot
   mov eax, dword ptr squareroot
   mov edx, dword ptr [squareroot+4]
   invoke sprintf, addr szBuf, offset $interm, eax, edx
   invoke MessageBoxA, 0, addr szBuf, offset _title, 0
   invoke ExitProcess, 0



main ENDP
END main, 0, addr szBuf, offset _title, 0
   invoke ExitProcess, 0

Should print "123.5642+654.4321"

Assume you have squareroot = 123.5642 and sqareroot2 = 654.4321

Is there any website or book with documentation regarding this?
I'm not sure if the Intel manual is meant for beginners.

Title: Re: Printing floating point not working.
Post by: aw27 on August 17, 2017, 05:52:28 PM
As someone has recommended to you before, try to use a debugger to see how things are processed.

The sprintf does not care about edx:eax, If you see with a debugger you will see that it pushes edx and then pushes eax. Both pushes will make a REAL8.

As mentioned yesterday, just push the variables directly and forget about what I did.



Title: Re: Printing floating point not working.
Post by: jj2007 on August 17, 2017, 09:06:20 PM
I have another question about printing.

If you had posted a complete snippet, from include ... to ... end start, I would have considered looking at it.
Title: Re: Printing floating point not working.
Post by: Chris. on August 17, 2017, 10:07:02 PM
I added whole code if it helps
Title: Re: Printing floating point not working.
Post by: jj2007 on August 17, 2017, 11:12:16 PM
I added whole code if it helps

It helps:
Code: [Select]
Finished:
   fstp squareroot
   if 1
    .DATA
$interm8 db "%0.20f",13,10,0
    .CODE
invoke sprintf, addr szBuf, offset $interm8, squareroot
   else
; $interm db "%0.4f + %0.4f",13,10,0
mov eax, dword ptr squareroot
mov edx, dword ptr [squareroot+4]
invoke sprintf, addr szBuf, offset $interm, eax, edx
   endif

If I guessed right, you want to print the squareroot, which you declared inconsistently as dq. Assemblers are tolerant, but they should shout foul instead. QWORD is an integer, you want an 8-byte float. They are commonly called "double" in C land, or REAL8 in assembly. As a matter of fact, the invoke macro knows how to handle them.

P.S.: The if 1 ... else ... endif part is called conditional assembly: just put if 0 to build your old version.
Title: Re: Printing floating point not working.
Post by: raymond on August 18, 2017, 05:10:24 AM
Chris,
To answer your very first question, the answer is YES. Floating point numbers CAN be printed directly from an fpu register. However, if you don't know how to do it, you can use some other external procedures until you have learned how to use assembly, including fpu mnemonics, to do it yourself. One such procedure is included in the Fpulib available on the same site where you read (but did not understand) the description of the 'fist' instruction. If you are really interested, that library also comes with the code for each of the procedures.

Quote
I thought the "fist" instruction allows you to store fpu numbers into memory or variables.
It does allow you to store it into a memory variable but as its ROUNDED INTEGER, rounded according to the content of the fpu's Control Word (http://www.ray.masmcode.com/tutorial/fpuchap1.htm#cword). Once rounded, that integer CANNOT be converted back to the original float; and trying to print that as a float would only yield garbage.

As for your recent question
Quote
What if i want two different variables in one string?
, whether you have two, three, or 100+, the only way in assembly is to build the string one variable at a time yourself in a buffer before printing it.
Title: Re: Printing floating point not working.
Post by: RuiLoureiro on August 18, 2017, 08:24:43 AM
Hi
    Here how to convert to string to print
    or string to real10

    http://masm32.com/board/index.php?topic=1852.0 (http://masm32.com/board/index.php?topic=1852.0)
    http://masm32.com/board/index.php?topic=1914.msg19899#msg19899 (http://masm32.com/board/index.php?topic=1914.msg19899#msg19899)