News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Working With the FPU

Started by grubish, April 27, 2011, 07:55:41 PM

Previous topic - Next topic

grubish

Hey Everyone,
      I'm back again with one of my doubts that needs to be cleared. I been trying to work with floating point numbers for a while and get a feel of it. So long story short, I have decided to write a piece of code that will compare three variables and print the largest amongst them. I know it sounds easy! And I feel the same way too.

My question is - Should I take the user input in a QWORD, then invoke StrtoFloat. Then invoke FpuComp (see for the RETURN value in EAX) and logically  build the algorithm ? Or should i just take the user input in REAL8 datatypes, load the numbers in FPU and compare ?

Disclaimer - I'm not asking anyone to show me the code or even pseudo-code it for me. I just intend to know which one's the right way to go about it.

Thank you.
-grubish-

MichaelW

I think you would learn more if you used the FPU directly. If by user input you mean the user typing in a string that represents a floating-point value, you will need to convert the string to an appropriate number before you can load it into the FPU.
eschew obfuscation

grubish

Yea, the user will type in the string from the standard input. So, I'm guessing the algorithm should be something like ...

1) user input and convert it to float
2) invoke FpuComp and pass the pointer of the converted value (Float) to the PROC and then check EAX for CMP_EQU or CMP_GREATER or CMP_LOWER

What're your thoughts on that ?
-grubish-

jj2007

Whatever routine for conversion you use is not so important. You need to see with your own eyes what's happening in the FPU, and only Olly can show you that. Especially the barrel principle is difficult in the beginning - the FPU behaves a bit like the stack, but in a more complex way.

Here is a template for playing around...

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; Download
.data?
Num1   REAL10 ?
Num2   REAL10 ?
  Init
  .Repeat
   MovVal Num1, Input$("Type the first number and hit Enter:  ")
   MovVal Num2, Input$("Type the second number and hit Enter: ")
   Print "Your numbers are ", Str$(Num1), " and ", Str$(Num2), CrLf$
   ; int     ; activate to have a look at your numbers in Olly
   fld Num1
   fld Num2
   deb 4, "You can see them on the FPU", ST(0), ST(1)   ; debug macro for console mode
   fstp st
   fstp st
   Fcmp Num1, Num2
   .if Carry?
      Print Str$("Num1 at %f is lower than ", Num1), Str$(Num2), CrLf$
   .elseif Zero?
      Print "Numbers are equal", CrLf$
   .else
      Print Str$("Num1 at %f is higher than ", Num1), Str$(Num2), CrLf$
   .endif
   Inkey "Press y for another round", CrLf$, CrLf$
  .Until eax!="y"
  Exit

end start

Sample output:
Type the first number and hit Enter:  12.34
Type the second number and hit Enter: 12.45
Your numbers are 12.34000 and 12.45000

You can see them on the FPU
ST(0)           12.4500000000000000
ST(1)           12.3400000000000000
Num1 at 12.34000 is lower than 12.45000
Press y for another round

grubish

Okay, i took your idea and played around with it for a while. But I don't know how correct I'm.


.386
.model flat, stdcall
option casemap: none

include \masm32\include\kernel32.inc
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\Fpu.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\Fpu.lib

.data
msg db "Enter a Floating Point Number", 10, 13, 0
buff dw 10 DUP(?)
value dw 10 DUP(?)
result db "They are Equal", 10, 13, 0
notresult db "Not Equal",0
buff1 dw 10 DUP(?)
value1 dw 10 DUP(?)

.code

start:
invoke StdOut, addr msg
invoke StdIn, addr buff, 10

invoke StdOut, addr msg
invoke StdIn, addr buff1, 10

invoke StrToFloat, addr buff, addr value
invoke StrToFloat, addr buff1, addr value1

invoke FpuComp, addr value, addr value1, SRC1_REAL or SRC2_REAL
test EAX, CMP_EQU
jz equal

jmp notequal


equal:

invoke StdOut, addr result

notequal:
invoke StdOut, addr notresult


invoke ExitProcess, 0
end start


Well, I've a feeling I'm way off the mark, since no matter what number I input... it prints both "result" and "notresult".
-grubish-

jj2007

test...
.if Zero?
   invoke StdOut, addr result
.else
   invoke StdOut, addr notresult
.endif

grubish

It works like a charm. It was suggested to me by MichaelW, that I should load the values into FPU. So i wrote another piece of code, using FPU.

.386
.model flat, stdcall
option casemap: none

include \masm32\include\kernel32.inc
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\Fpu.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\Fpu.lib

.data

val1 REAL8 12.10
val2 REAL8 20.11

.code
start:
finit
fld val1
fcom val2
fstsw EAX


invoke ExitProcess, 0
end start


Is that the way to do it ?
-grubish-

raymond

@grubish

I get the impression that you are using an older version of the Fpulib. If you wish to continue to use that older version, you must be aware that it accepts only extended double precision floats (80 bits, 10 bytes) as input for most functions. Then, you should also check what type of floats may be returned by funcions outside of the Fpulib, such as the StrToFloat from the m32lib. That one happens to return 64-bit floats.

The way you had your memory variables set up, The FpuComp function may have seemed to work OK but it certainly did not load the proper 80-bit floats as specified for comparison.

The latest Fpulib has expanded options for the data types which can be used with the lib functions. You can get the latest version v2.33 from:
http://www.ray.masmcode.com/fpu.html#fpulib

Be sure to read AND understand the help file as to the requirements of each function you intend to use.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

grubish

Hey Raymond,
       Thanks for the heads up and the tips. Actually in the previous code where I use the FpuLib works okay ;but What I'm trying to wrap my head around is this. In this I take a input(DWORD) and convert it a REAL8 value. And I didn't thoroughly read the Fpulib, but the fld seems to convert the REAL4 or REAL8 values to REAL10 (80 bit) ones. Here's what I have so far ... I'd like your inputs on that matter. Thanks.


386
.model flat, stdcall
option casemap: none

include \masm32\include\kernel32.inc
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\Fpu.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\Fpu.lib

.data
msg db "Enter a floating point number", 10, 13, 0

crlf db 10, 13, 0
val1 REAL8 ?
var2 dw 10 DUP(?), 0
val3 REAL8 ?
var3 dw 10 DUP(?), 0
val2 REAL8 ?
var1 dw 10 DUP(?), 0


.code
start:

invoke StdOut, addr msg
invoke StdIn, addr var1, 10



invoke StdOut, addr msg
invoke StdIn, addr var2, 10

invoke StdOut, addr msg
invoke StdIn, addr var3, 10

invoke StdOut, addr crlf



finit

fild var1
fstp val1

fild var2
fstp val2

fild var3
fstp val3

fld val1
fcom val2
fstsw AX
fwait
sahf

ja one_greater
jb one_lower
jz onetwo_equal
               
                ......



It seems to be working fine for the most part except for some glitches. I'm trying to get a better solution.
-grubish-

jj2007

You cannot fld a string onto the FPU. Some conversion is needed. Check the FPU lib for conversion, or use MasmBasic together with OllyDbg

MovVal Num1, Input$("Type the first number and hit Enter:  ")
int 3 ; Olly will stop here
fld Num1 ; see what happens

grubish

 I have used fld on var1 and var1 is a REAL8. And i have converted it using


fild var1
fstp val1



So here's the thing, I can print the lowest floating point number, but when say (a, b and c are three floating point number) and when ( a==b | b==c|c==a) and lowest, and i try to print those two values, i get nothing. It's really weird.
-grubish-

jj2007

Quote from: grubish on April 28, 2011, 09:30:11 AM
I have used fld on var1 and var1 is a REAL8. And i have converted it

Njet. You haven't converted anything. You are passing a string, not a numeric value. Of course, the FPU will try to interpret the string as a REAL4, but you get rubbish. USE OLLY.

invoke StdIn, addr var1, 10  ; var1 contains a string

grubish

ah okay, got you. So, can I use StrToFloat and then use FLD on the converted value ?
-grubish-

bomz

Quote
--------------------------------
AReg            WORD64 ?
CReg            dt ?
--------------------------------
finit
fild AReg
fbstp CReg
--------------------------------
Thats work - convert to compress 10

jj2007

Quote from: grubish on April 28, 2011, 09:38:59 AM
can I use StrToFloat and then use FLD on the converted value ?

Exactly. Alternatively, use MovVal as shown in reply #3.

And it would be even better if you learned how to use Olly, otherwise you will continue playing around without understanding anything.