News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Printing floating point not working.

Started by Chris., August 16, 2017, 03:40:24 AM

Previous topic - Next topic

Chris.

.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?

aw27

I don't understand this;
$interm dword "%fl",13,10,0

then:
fist $interm

Chris.

I thought the "fist" instruction allows you to store fpu numbers into memory or variables.
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


jj2007

Quote from: Chris. on August 16, 2017, 03:40:24 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:

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,
$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:
.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.

aw27

This does not produce errors. You will have to check what is different from yours:


.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

Chris.

#5
Ok thanks,  I read this guide: (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?

jj2007

Quote from: Chris. on August 17, 2017, 03:31:24 AMFor 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?

Chris.

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?

aw27

#8
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

jj2007

Quote from: Chris. on August 17, 2017, 04:42:15 AMAre 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.

nidud

#10
deleted

habran

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 
Cod-Father

Chris.

#12
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


.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.


aw27

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.




jj2007

Quote from: Chris. on August 17, 2017, 03:55:28 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.