News:

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

FPU doesn't see a real8 value of 0.0 properly

Started by braincell, March 29, 2012, 07:06:25 PM

Previous topic - Next topic

dedndave

Quote from: braincell on March 29, 2012, 09:23:27 PMI can't really "see" the code as it's only passed as an array of bytes, randomly generated

:bg

when you're done, you can write a book...
Learning Assembly Language, The Hard Way

braincell

Err yea  :8)

For what it's worth, the problem ended up being this: it's that my array of Double (real8) included NaNs and when they reached my MASM dll and were included in some computations, it only showed them as 0.0 in debug, so i didn't notice.
Any computation which included a NaN ended up being well ... just that.
I guess i expected exceptions where there arent any.
This is a "well duh" moment, but yeah, i learn a lot. The hard way.

braincell

BTW, what's the best way to check if a number on the FPU (REAL10) or in memory (REAL8) is NaN?

What's better of these two:

Method #1


                        fld MyReal8
fxtract
fstp st(0)
fistp dbg_test_Xponent

mov ax, dbg_test_Xponent
cmp ax, 32768
jne dbg_Not_NaN

deb 5, " exponent detected NaN value ..."

                dbg_Not_NaN:



Method #2


        fld MyReal8
fcomp SomeValidConstant
        fstsw ax
sahf

jpe dbg_IsNaN
jmp dbg_IsNotNaN

dbg_IsNaN:
    ;NaN detection code
dbg_IsNotNaN:
    ;no NaN detected...



dedndave

the status word is the easiest way
there are a few value formats that constitute NaN's, so it would probably take more code to check all of them
if all the exponent bits are 1's and one or more of the mantissa bits is 1, it is a NaN

you'd have to time it, but i suspect the status word is faster
        push    eax
        fstsw word ptr [esp]
        pop     eax         ;AX = status word


as far as "strange" code goes, i am a big fan - lol
a while back, Jochen and i had a personal contest to see who could build a table in the fewest bytes of code
i think i won by a few bytes - look at the Gen10 and Cor10 PROC's....

braincell

Hmm ok i'll have to test it a bit. Right now only Sqrt() of negative numbers and 0 division is giving me problems. I can throw out those operators completely as the don't contribute much to my solutions, and i keep the speed AND integrity. Nifty.

I had a look at the code.
Are you that guy that coded the program for a Pacemaker? 4k of memory due to low power, using 1 bit of memory for multiple purposes, etc? Yeah, crazy.
I'd probably need pencil and paper to draw out what your code does, but it looks clever. Maybe when i go on holiday that can be my hobby. :)

dedndave

nah - that wasn't me
i am going to be famous for winning half a billion in the mega lottery   :U
then i am gonna change my name, so i won't be famous again

MichaelW

Quote from: braincell on March 29, 2012, 09:07:24 PM
I thought that if i did FLD into a full register that i would get a stack overflow, or some other kind of program-halting problem.

The FPU normally handles exceptions internally, but you can enable the FPU to generate external interrupts for specific exceptions, and so trigger an exception that a debugger can catch.

;==============================================================================
include \masm32\include\masm32rt.inc
.686
;==============================================================================

;-----------------------------------------
; Values for the FPU interrupt mask bits.
;-----------------------------------------

FIM_INVALID      equ 1
FIM_DENORMALIZED equ 2
FIM_ZERODIVIDE   equ 4
FIM_OVERFLOW     equ 8
FIM_UNDERFLOW    equ 16
FIM_PRECISION    equ 32
FIM_ANY          equ 63

;--------------------------------------------------------
; This macro selectively clears the FPU interrupt masks.
; Example usage: FCLEARIM FIM_ZERODIVIDE or FIM_OVERFLOW
;--------------------------------------------------------

FCLEARIM MACRO maskbits
    push eax
    fstcw [esp]
    pop eax
    and ax, NOT (maskbits)
    push eax
    fldcw [esp]
    pop eax
ENDM

;==============================================================================
.data
    r8      REAL8 ?
    r10max  REAL10 1.18E4932  ; Approximate
    r10min  REAL10 3.37E-4932 ; Approximate
.code
;==============================================================================
start:
;==============================================================================
    finit

    fldpi
    fldz
    fdiv
    fstp r8

    inkey

    ;FCLEARIM FIM_ZERODIVIDE
    ;fldpi
    ;fldz
    ;fdiv
    ;fstp r8

    ;FCLEARIM FIM_INVALID
    ;REPEAT 9
    ;    fldpi
    ;ENDM
    ;fstp r8

    ;FCLEARIM FIM_OVERFLOW
    ;fld r10max
    ;fld r10max
    ;fmul
    ;fstp r8

    FCLEARIM FIM_UNDERFLOW
    fld r10min
    fld r10max
    fdiv
    fstp r8

    inkey
    exit
;==============================================================================
end start

#define STATUS_FLOAT_DENORMAL_OPERAND  ((NTSTATUS)0xC000008DL)
#define STATUS_FLOAT_DIVIDE_BY_ZERO    ((NTSTATUS)0xC000008EL)
#define STATUS_FLOAT_INEXACT_RESULT    ((NTSTATUS)0xC000008FL)
#define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS)0xC0000090L)
#define STATUS_FLOAT_OVERFLOW          ((NTSTATUS)0xC0000091L)
#define STATUS_FLOAT_STACK_CHECK       ((NTSTATUS)0xC0000092L)
#define STATUS_FLOAT_UNDERFLOW         ((NTSTATUS)0xC0000093L)

eschew obfuscation

braincell

Quote from: MichaelW on March 30, 2012, 12:54:35 AM

The FPU normally handles exceptions internally, but you can enable the FPU to generate external interrupts for specific exceptions, and so trigger an exception that a debugger can catch.


Ah! So that's how the pros do it. Ok, cheers, code saved for future use.

raymond

I would suggest that you read at least once more the description of the "Status word" in Chap. 1 of Simply FPU.

Whenever there may be a risk of an invalid instruction in my programs, I simply add the following code before continuing to use a result from a computation:

fstsw ax
test al,1
jz everything_valid
fclex  ;rezero the exception flags, once set, they don't get reset otherwise
;include code or set flags to cope with an invalid operation
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

vanjast

May I suggest going through Ramond's Simply FPU thoroughly...as well as Intels doccies  :wink

dedndave

Ray can only do so much   :P
generating random code to see what happens is a bit "hit-and-miss" - lol
better to try each instruction, individually - play with it until you are comfortable, and move on to the next one

for all its' complexities, i always thought the FPU was pretty simple to learn
a little trickier back in the old days - the 8087 had a few more buttons to mash
things like "affine" or "projective" infinity - huh ?   :eek
maybe Ray could add an 8087 addendum to his tutorials (lest it be forgotten in the annals of time)
should be required learning for math majors in college   :bg