I have two problems to solve in x87 ASM and I'm a little confused by it, could anyone suggest some ideas?
Equation: 1-(x/y)
Background: X and Y are always positive floating point numbers, but the result of the calculation can be either positive or negative. This is part of a wider calculation which always results in a positive number.
Problem 1: Either X or Y can be zero (and both can be zero simultaneously). Divide by zero is bad. However if either value is zero, I want the final result to be "1" (i.e. Fld1, pop any unnecessary numbers and then move on)
Problem 2: The result must always fall between -1 and +1. If the result is above 1 or below -1, I just want to replace the result with 1. (I.e. In the case of 1-(35/0.01).)
So far I have the following:
fld dword [y] ; Check if either number is 0
fmul dword [x] ;
Fldz
fcomip st(1),st(0)
je exit_1 ; If result is zero jump outta here
fld dword [y] ; Otherwise load the floats
fld dword [x]
fdivp ; Do X/Y
fld1
fsubrp ; 1 - X/Y
????? ; Need some code here to check result is between -1 and 1. If not, replace the result with "1" every time.
.exit_1
fld1 ; Use 1 as the result for the next calculation
jump to_next_calc
In order to the value of 1 - x/y
to go below -1, x/y > 2
, meaning that you can early exit with
if (x >= (y + y)) return -1.0f;
Having =
also handles the case of x==0 and y==0
, where as the >
handles the case of x>0 and y==0
.
Then proceed normally and the output is limited to [-1 .. 1]
automatically.
The multiplication of y
by two can be theoretically speeded up by adding 1 to the exponent - given that the number is not denormal, inf, or nan, and does not overflow...