Hello everybody,

The following code multiplies two predefined numbers:

Operand1 REAL8 32.0
Operand2 REAL8 8.0
Result dq 0


finit
fld Operand1
fld Operand2
fmul st(0),st(1)
fstp Result
invoke FloatToStr,Result,offset TempBuf

How is it possible to load numbers into Operand1 and Operand2 variables?


best regards,

czDrillard
Posted on 2003-11-07 22:10:02 by czDrillard
via stack?
Posted on 2003-11-07 22:48:00 by roticv
fld means that the contents of memory is loaded to FPU register (specifically, st(0)), not the reverse.
Posted on 2003-11-08 00:17:31 by Starless
...and fstp stores the contents of st(0) into the variable and pops it from the FPU stack.
It should be converted to the corresponding FP format depending on the size of the variable. So the following:
fstp Operand1

will store the contents of st(0) as a REAL8.
Posted on 2003-11-08 08:06:23 by QvasiModo
How is it possible to load numbers into Operand1 and Operand2 variables?
There are 3 ways to do it.

The first one is to initialize the variable in the .data section as you seem to already know how.

The second way is to calculate values (such as the coordinates of the apex of a tetrahedra, or whatever) and store the results in the variables as you also seem to know how. (Integer values can simply be kept in integer variables and still be fully available for use in the FPU.)

The third way is to request information from the user. That information is usually recovered in the form of an alphanumeric string which must be converted to the proper binary format, either integer or floating point. You can either code that conversion yourself or (until you get more familiar with FPU instructions) use some library function, such as the FpuAtoFL in the fpu.lib which you can find at the end of the following thread:
http://www.asmcommunity.net/board/index.php?topic=9717&highlight=fpulib

You may also get some usefull information in the following tutorial:
http://www.masmforum.com/website/tutorials/fptute/index.html

Raymond
Posted on 2003-11-08 10:12:12 by Raymond
Hello everybody,

Thanks for all the replies. Raymond, thankyou for the excellent help file and the tutorials. I've been studying them for some time and found they remove some of the mystery out of the FPU. :)

this dosen't work:

Operand1 REAL8 0.0
Operand2 dd 0
Result dq 0


finit
lea eax,Operand1
mov dword ptr ,32
fld dword ptr
mov Operand2,8
fmul Operand2
fstp Result
invoke FloatToStr,Result,offset TempBuf


this code results in 5.026912e-088 should be 256 ??

How to load two numbers generated at run time and multilply them together using the FPU?

Any help much appreciated,

best regards,

czDrillard
Posted on 2003-11-08 11:22:53 by czDrillard
You have to make the fpu to convert the integers into fp and vice versa.

At a first glance, i would do this:



Operand1 dd 0
Operand2 dd 0
Result dd 0

finit
lea eax,Operand1
mov dword ptr [eax],32
fild dword ptr [eax]
lea eax,Operand2
mov dword ptr [eax],8
fild dword ptr [eax]
fmul st(0),st(1)
fistp Result


Notice the "fild" to load an integer into a fp register.
Notice also the "fistp" to return it as an integer from a fp register.

If the variable Result have to be a quad word then use "fstp" (but the format will need to be converted because it will not be in decimal notation).

h.
Posted on 2003-11-08 11:49:21 by hitchhikr
Thanks hitchhikr

That works but I need to use real numbers for variables. I will be dividing two integers then multiplying the result. The result will usually be a decimal fraction.

Btw, I'm doing all this to scale my dialog boxes and re-set some of the controls.

best regards,

czDrillard
Posted on 2003-11-08 12:36:34 by czDrillard
Just remember that you need to use fistp to store/convert a fp value into an integer (and fild to do the other way round).

also "frndint" can be of some use to convert fp -> integer.

h.
Posted on 2003-11-08 12:57:34 by hitchhikr
Btw, I'm doing all this to scale my dialog boxes and re-set some of the controls
For this type of usage, you don't need the higher precision of REAL8 numbers. The REAL4 has sufficient precision and sufficient range.

Assuming the 1st division of 2 integers (in EAX and EDX for this example) is to get the ratio which will be used to scale several other dimensions,
.data?

ratio REAL4 0
integer1 dd 0
result dd 0

.code
mov integer1,eax
fild integer1
mov integer1,edx
fidiv integer1
fstp ratio ;store the ratio and free the FPU

......

;get an integer to be scaled into EAX
mov integer1,eax ;store it in a memory variable
fild integer1 ;load it to the FPU from memory
fmul ratio
fistp result ;store the scaled dimension and free the FPU

The latter result is a rounded integer as you would require for a scaled dimension. A result with a fractional portion would not be of much use in this context.

Raymond
Posted on 2003-11-08 22:05:56 by Raymond
Thanks Raymond, I am using very similar code other than Result must be dq type data in order to use the following code:


invoke FloatToStr,Result,offset TempBuf
xor eax,eax
invoke atodw,ADDR TempBuf
mov x,eax

Then I pass x to the CreateWindowEx function to set x location.

best regards,

czDrillard
Posted on 2003-11-09 15:11:43 by czDrillard
Unless you MUST have the result as an ascii string for some other purpose, you are taking some un-necessary high risk using that quoted route.

1st, if I remember correctly, the FloatToStr funjction returns a string with some fractional decimal digits. You are not getting a rounded integer string.

2nd, again if I remember correctly, the atodw function does not check the string for errors. One version I have seen treats all characters as numerical digits up to the terminating 0! The returned result may be useless.

My suggested code would place your required result directly into your "x" variable. NO RISK and rounded.

Raymond
Posted on 2003-11-09 22:20:10 by Raymond
Raymond, I have changed my code to match yours and not using FloatToStr function.

Btw, I was calling frndint before popping stack to ensure no decimals...it all seemed to work fine but why have all the unecessary overhead:grin:

Thankyou very much for your time and help.

best regards,

czDrillard
Posted on 2003-11-10 00:02:06 by czDrillard
czDrillard

For your particular application, you could also look at using fixed point maths and do all the computation with the CPU instead of the FPU.

This involves using part of the dword for the integer portion and the remaining part for the fraction, the size of each being based on current needs. For example, the H.O. 16 bits of a dword for the integer portion allow a range of +/- 64k for unsigned values, and the remaining L.O. 16 bits for the fraction would be equivalent to approx. 5 decimal places.

Again assuming you don't need to convert the scaled value to ascii with a decimal portion for some other purpose, the code could look like the following. It assumes that the two values required to compute the scaling ratio are already in EAX and ECX.
.data

ratio dd 0
x dd 0

.code
shl eax,16 ;shift numerator to H.O. 16 bits
cdq ;clears EDX for the division
div ecx ;result in EAX with a 16-bit fraction
mov ratio,eax

....

mov eax,[I]value_to_be_scaled[/I]
mul ratio
shr eax,16 ;get rid of the fraction
jnc @F
inc eax ;round it if fraction >= 1/2
@@:
mov x,eax


The beauty of assembler!!!:tongue:

Raymond
Posted on 2003-11-10 07:37:48 by Raymond
I'll file that away for future reference. An elegant piece of code Raymond, serving as a reminder of the versatility of assembler.

best regards,


czDrillard
Posted on 2003-11-10 09:29:49 by czDrillard