News:

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

Floating point math

Started by ecube, April 10, 2009, 02:47:40 PM

Previous topic - Next topic

ecube

The only disadvantage I see ASM having over C++ and other high level languages is math IMO a lot harder.FPU is still real confusing to me even though i've read docs on it, and looked throughout this board. And since i'm working on a preprocessor for GoASM to add .if etc.. support I thought why not add complicated math support. My goal is to support somthing like

CODE SECTION
invoke writefile etc...

M(9.81 - 9)

or

mov ecx,7
M(ecx + 5.31)

and the results in the eax


the preprocessor recognizing the M() replaces it with code that does the math and puts it in eax before the assembler sees it. So if possible can someone provide a simple example of FPU addition or give any tips on a better way I should approach this?. This is being written for GoASM but can be used to preprocess anything MASM,Fasm etc...

dedndave

yes - the FPU is fun to learn - lol
especially things like "affine" or "projective" infinity and error handling
I try to look at it as a way to renew my math skills - lol - it helps
in a way, I was lucky because I wrote code for the 8087 math co-processor
the 8087 is a simplified version of what is in the pentiums
well, at least, it was easier to learn
some things have gotten easier because they added several new instructions to do some of the work for you


raymond

There's very little you can do with a 32-bit single precision float in the IEEE floating point format in any of the ALU general purpose registers, apart from storing it in memory and a few other minor tasks such as verifying its sign , comparing it to some other 32-bit float, etc.

What were your intended reasons for using such registers for floats?

Other (HLL) languages use only memory variables specificly declared as floats (either single, double or extended precision) to receive the result of any float operation.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

ChrisLeslie

A routine that parses one-liner floating point expressions with mixed variables and constants would be a real time saver in my opinion. No assemblers do this at present.  Each expression therefore involves many lines of code, one for each component of the expression, and are generally not very easy to grasp mathematically at a glance. My applications involve lots of long expressions, therefore I have not been pursuing assembler these days but using unmentionable languages simply because of their floating point expression parsing capabilities. Cubie, achieving this in Goasm, with tidy syntax, would be terrific.  :U

ecube

well raymonds nice fpulib which he didn't mention looks like it'll do all the FPU stuff I need. so I'll play with it, then write some syntax parsing code so can do things like


buff db 255 dup(?)
num REAL10 ?

;to do the math,convert to string and put in the buffer
buff = Mst(10.9 + 5.31 * 5 - 3 / 2)

invoke MessageBox,addr buff,'test results',mb_ok

;to do the math,and save in the real10 variable
num = M(10.9 + 5.31 * 5 - 3 / 2)


and yeah ChrisLeslie this would be great to have, will be another way to convince more of my customers to use Assembly over HLL, and let me do the math I always wanted to without using C++.

dedndave

I am sure Rays lib has something like what you are looking for
If not, he has the routines that could be glued together to make it

jj2007

Quote from: ChrisLeslie on April 11, 2009, 08:53:09 AM
A routine that parses one-liner floating point expressions with mixed variables and constants would be a real time saver in my opinion. No assemblers do this at present.

Some time ago I tried my luck:

Let MyResult=68.16122-G2*(f1+3*1.8**2.2)+G2*f1

Output sample:

G1=12.34, G2=43.21 (both global REAL10)
f1=11.11, f2=22.22 (both local REAL10)

Calculating 68.16122-G2*(f1+3*1.8**2.2)+G2*f1 :
Expected value is       -404.2335
Calculated value is     -404.2335
-- Second operand is smaller

Calculating 4-G1*(f2-3.4)+G2*f1 :
Expected value is       251.8243
Calculated value is     251.8243
** Operands are equal or almost equal at 8 digits precision


It works, produces tiny and fast code, but the macros needed to perform this have over 400 lines. You are likely to be stoned for heresy in this forum for such misuse of Masm features :boohoo:

raymond

A few words of caution.

Your parser would effectively add code instructions to handle those "equations". Those instructions would obviously use FPU registers. If the user tries to use the FPU registers (with FPU or MMX code) on his own for some other operations and leaves data in some of those registers (either intentionally or not), your instructions may trash some of that data or you may be short of working registers if you don't take proper precautions.

Using calls to the fpulib would certainly avoid the above but would definitely add runtime overhead. One suggestion would be to use the parser to first convert all constants with decimal digits to floats and create global variables to receive them (assembly runtime). Then insert calls to the appropriate functions to perform the required computations with these floats and any other variables which may change at runtime.

If you could be absolutely certain that the user would not use any of the FPU registers, you could use only the required FPU instructions without all the overhead of the fpulib. (But then it's your duty to cleanup the FPU registers. :dance:)
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

ecube

jj2007,
as mentioned above i'm not writing a macro, i've already pretty much finished a preprocessor for GoASM that adds .if,.endif etc.. support. It does this by preprocessing the source file before GoASM see's it and generating code in a temp file in place of the conditional statements. My goal next is to add FPU math support aswell, this preprocessor can be used for any assembler, not just GoASM, but that'll be its first target. In MASM32 10 hutch included a library called FPULIB written by Raymond which does all the FPU math I believe is necessary, so it's just a matter of me crawling my way through mathmetics using his functions to generate correct code.

Raymond,
thanks for the advice, I hope once I have something working you take a glance at the source and if you see any problems you let me know. As stated my math skills are pretty weak even though I have a degree in computer science. But I am persistant.

jj2007

Quote from: E^cube on April 12, 2009, 08:23:12 AM
jj2007,
as mentioned above i'm not writing a macro, i've already pretty much finished a preprocessor for GoASM that adds .if,.endif etc.. support. It does this by preprocessing the source file before GoASM see's it and generating code in a temp file in place of the conditional statements. My goal next is to add FPU math support...

What you intend is basically what MASM macros do already: Take .if ... .endif as input and generate cmp... jxx code. That's fine for me, but when applied to the FPU, the difference is complexity. The simple statement

Let MyResult=68.16122-G2*(f1+3*1.8**2.2)+G2*f1

produces the code below. It is less safe than what Raymond's lib would have produced, but shorter and roughly twice as fast. And completely uncomprehensible...! That is why I can't see this community here accept a preprocessor that generates opaque code. How often do you read statements here saying macros are evil attempts to destroy the purity of assembler...?



CPU Disasm
Address               Hex dump                       Command                                                                  Comments
0040118B              ³> 68 7A016800                 ³push 68017A
00401190              ³. DB0424                      ³fild dword ptr [esp]
00401193              ³. 58                          ³pop eax
00401194              ³. 68 A0860100                 ³push 186A0
00401199              ³. 8BF6                        ³mov esi, esi
0040119B              ³. DA3424                      ³fidiv dword ptr [esp]
0040119E              ³. 58                          ³pop eax
0040119F              ³. DDD2                        ³fst st(2)
004011A1              ³. DDC0                        ³ffree st
004011A3              ³. D9F7                        ³fincstp
004011A5              ³. DB2D FE494000               ³fld tbyte ptr [4049FE]                                                  ; float 43.210000000000000850
004011AB              ³. DDD3                        ³fst st(3)
004011AD              ³. DDC0                        ³ffree st
004011AF              ³. D9F7                        ³fincstp
004011B1              ³. DB6D CC                     ³fld tbyte ptr [ebp-34]
004011B4              ³. DDD4                        ³fst st(4)
004011B6              ³. DDC0                        ³ffree st
004011B8              ³. D9F7                        ³fincstp
004011BA              ³. 6A 03                       ³push 3
004011BC              ³. DB0424                      ³fild dword ptr [esp]
004011BF              ³. 58                          ³pop eax
004011C0              ³. DDD5                        ³fst st(5)
004011C2              ³. DDC0                        ³ffree st
004011C4              ³. D9F7                        ³fincstp
004011C6              ³. 6A 12                       ³push 12
004011C8              ³. DB0424                      ³fild dword ptr [esp]
004011CB              ³. 58                          ³pop eax
004011CC              ³. 6A 0A                       ³push 0A
004011CE              ³. 8BF6                        ³mov esi, esi
004011D0              ³. DA3424                      ³fidiv dword ptr [esp]
004011D3              ³. 58                          ³pop eax
004011D4              ³. DDD6                        ³fst st(6)
004011D6              ³. DDC0                        ³ffree st
004011D8              ³. D9F7                        ³fincstp
004011DA              ³. 6A 16                       ³push 16
004011DC              ³. DB0424                      ³fild dword ptr [esp]
004011DF              ³. 58                          ³pop eax
004011E0              ³. 6A 0A                       ³push 0A
004011E2              ³. 8BF6                        ³mov esi, esi
004011E4              ³. DA3424                      ³fidiv dword ptr [esp]
004011E7              ³. 58                          ³pop eax
004011E8              ³. D9C6                        ³fld st(6)
004011EA              ³. E8 11FEFFFF                 ³call 00401000                                                           ; [Parser.00401000
004011EF              ³. DDD6                        ³fst st(6)
004011F1              ³. DDC0                        ³ffree st
004011F3              ³. D9F7                        ³fincstp
004011F5              ³. D9C5                        ³fld st(5)
004011F7              ³. D8CD                        ³fmul st, st(5)
004011F9              ³. DDD5                        ³fst st(5)
004011FB              ³. DDC0                        ³ffree st
004011FD              ³. D9F7                        ³fincstp
004011FF              ³. D9C4                        ³fld st(4)
00401201              ³. D8C4                        ³fadd st, st(4)
00401203              ³. DDD4                        ³fst st(4)
00401205              ³. DDC0                        ³ffree st
00401207              ³. D9F7                        ³fincstp
00401209              ³. D9C3                        ³fld st(3)
0040120B              ³. D8CB                        ³fmul st, st(3)
0040120D              ³. DDD3                        ³fst st(3)
0040120F              ³. DDC0                        ³ffree st
00401211              ³. D9F7                        ³fincstp
00401213              ³. D9C2                        ³fld st(2)
00401215              ³. D8EA                        ³fsubr st, st(2)
00401217              ³. DDD2                        ³fst st(2)
00401219              ³. DDC0                        ³ffree st
0040121B              ³. D9F7                        ³fincstp
0040121D              ³. DB2D FE494000               ³fld tbyte ptr [4049FE]                                                  ; float 43.210000000000000850
00401223              ³. DDD3                        ³fst st(3)
00401225              ³. DDC0                        ³ffree st
00401227              ³. D9F7                        ³fincstp
00401229              ³. DB6D CC                     ³fld tbyte ptr [ebp-34]
0040122C              ³. D8CB                        ³fmul st, st(3)
0040122E              ³. DDD3                        ³fst st(3)
00401230              ³. DDC0                        ³ffree st
00401232              ³. D9F7                        ³fincstp
00401234              ³. D9C2                        ³fld st(2)
00401236              ³. D8C2                        ³fadd st, st(2)
00401238              ³. DDD2                        ³fst st(2)
0040123A              ³. DDC0                        ³ffree st
0040123C              ³. D9F7                        ³fincstp
0040123E              ³. D9C1                        ³fld st(1)
00401240              ³. DDD1                        ³fst st(1)
00401242              ³. DDC0                        ³ffree st
00401244              ³. D9F7                        ³fincstp
00401246              ³. 9B                          ³wait
00401247              ³. DFE0                        ³fstsw ax
00401249              ³. 25 DF000000                 ³and eax, 000000DF
0040124E              ³. 66:0BC0                     ³or ax, ax
00401251              ³.74 30                       ³je short 00401283
00401253              ³. 833D F0644000 02            ³cmp dword ptr [4064F0], 2
0040125A              ³.74 27                       ³je short 00401283
0040125C              ³. 60                          ³pushad
0040125D              ³. 8BF0                        ³mov esi, eax
0040125F              ³. 68 F4644000                 ³push offset Parser.004064F4                                             ; ÚArg2 = Parser.4064F4
00401264              ³. 56                          ³push esi                                                                ; ³Arg1
00401265              ³. E8 06160000                 ³call 00402870                                                           ; ÀParser.00402870
0040126A              ³. 6A 01                       ³push 1                                                                  ; ÚType = MB_OKCANCEL|MB_DEFBUTTON1|MB_APPLMODAL
0040126C              ³. 68 28404000                 ³push offset Parser.00404028                                             ; ³Caption = "FPU status error:"
00401271              ³. 68 F4644000                 ³push offset Parser.004064F4                                             ; ³Text = ""
00401276              ³. 6A 00                       ³push 0                                                                  ; ³hOwner = NULL
00401278              ³. E8 05170000                 ³call <jmp.&user32.MessageBoxA>                                          ; ÀUSER32.MessageBoxA
0040127D              ³. A3 F0644000                 ³mov dword ptr [4064F0], eax
00401282              ³. 61                          ³popad

ecube

jj2007,

The preprocessors job isn't to produce readable code, its job is to take the readable code you've written and convert it to code the assembler understands. But to make something clear, the code will still be a lot more readable then the deadlisting u posted because i'm basically just calling Raymond's FPU functions to do what needs to be done. Will people "accept" this? I don't know, I don't much care, I want inline math, and that's what i'm gonna get. On the same token if others do find this useful that'd be great, i'd be glad I could contribute something that made their coding experience more pleasant/easier.