This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Sample Floating Point Divide error?

Other Parts Discussed in Thread: CONTROLSUITE

In e.g. SPRUEO2A page 48 there is sample code for doing a floating point divide using the FPU.

For Y = A/B
DIV:
   EINVF32 R2H, R1H ; R2H = Ye = Estimate(1/B)
   CMPF32 R0H, #0.0 ; Check if A == 0
   MPYF32 R3H, R2H, R1H ; R3H = Ye*B
   NOP
   SUBF32 R3H, #2.0, R3H ; R3H = 2.0 - Ye*B
   NOP
   MPYF32 R2H, R2H, R3H ; R2H = Ye = Ye*(2.0 - Ye*B)
   NOP
   MPYF32 R3H, R2H, R1H ; R3H = Ye*B
   CMPF32 R1H, #0.0 ; Check if B == 0.0
   SUBF32 R3H, #2.0, R3H ; R3H = 2.0 - Ye*B
   NEGF32 R0H, R0H, EQ ; Fixes sign for A/0.0
   MPYF32 R2H, R2H, R3H ; R2H = Ye = Ye*(2.0 - Ye*B)
   NOP
                                                <-- insert here
   MPYF32 R0H, R0H, R2H ; R0H = Y = A*Ye = A/B
   LRETR

If B is very large (MAX FLOAT or close), then I am finding that the calculation of Ye underflows to zero, and the returned result is zero whatever the value of A.  Thus 1/1e38 and 1e38/1e38 both return zero instead of 1e-38 and 1.0 – both possible floating-point values,

Assuming this underflow is unavoidable, we would like to fix this to get +/-INF in these cases so that it is clear that something has gone wrong.  My idea is to add a check for Ye == 0 at the marked point and if true set Ye to INF (preferably with the same sign as B).

As I know little of assembler, my question is – is this possible and what are the instructions?

Regards, Giles

  • Giles,

    In the source code in controlSUITE (www.ti.com/conctrolsuite C:\ti\controlSUITE\libs\math\FPUfastRTS) there is a check for division by zero - see below. As it comes the line is commented out. 

    I've marked the compare that is done in RED - this sets a bit int he status register if the comparison is true. Then the move is conditional based on this bit (also in RED).   If you need to make further changes those are the types of operations you would use - compares and conditional moves and conditional negations.

    If you find the fast version is too lacking there is a much slower version in the normal codegen RTS library.   It is a speed accuracy tradeoff.

    FS$$DIV:

            EINVF32     R2H, R1H            ; R2H = Ye = Estimate(1/B)
            CMPF32      R0H, #0.0           ; Check if A == 0
            MPYF32      R3H, R2H, R1H       ; R3H = Ye*B
            NOP
            SUBF32      R3H, #2.0, R3H      ; R3H = 2.0 - Ye*B       
            NOP        
            MPYF32      R2H, R2H, R3H       ; R2H = Ye = Ye*(2.0 - Ye*B)
            NOP
    ; Next line: if commented out: 0.0/0.0 = 0.0
    ;            if not commented: 0.0/0.0 = infinity
    ;       MOV32       R2H, R0H, EQ        ; If A == 0.0, Ye = 0.0
            MPYF32      R3H, R2H, R1H       ; R3H = Ye*B
            CMPF32      R1H, #0.0           ; Check if B == 0.0
            SUBF32      R3H, #2.0, R3H      ; R3H = 2.0 - Ye*B
            NEGF32      R0H, R0H, EQ        ; Fixes sign for A/0.0
            MPYF32      R2H, R2H, R3H       ; R2H = Ye = Ye*(2.0 - Ye*B)
            NOP
            MPYF32      R0H, R0H, R2H       ; R0H = Y = A*Ye = A/B
            LRETR
               .endasmfunc

  • Many thanks for the above.  I've managed to get it doing what I want.

    A further question though - is it known at what value EINVF32 underflows?

    We need to fully specify our floating-point functions (including valid input ranges), and this depends upon the valid range for EINVF32.

    Regards.

  • Giles Robnson said:
    A further question though - is it known at what value EINVF32 underflows?

    If the exponent (I'll call it E) is 255 (corresponds to NaN or infinity input) then zero is generated and the LUF flag is set.

    If that is not the case, the mantissa (I'll call it M) is inspected and we estimate the exponent of the result (i.e. Ee is the exponent of the Ye = 1/X extimate)

    if M[22:16] is 0, calculate Ee = 254 - E

    else Ee = 253 - E

    if the value of Ee above is <= 0, then we underflow. return 0 and set LUF.

    Hope this helps

    Lori

    edit: typo fixed