; math_exponents.asm
;
; Assembly language source for the 2**x, 
; e**x, 10**x, and y**x functions:


            include math.inc
            include aoalib.inc
            
;  TwoToX(x)- Computes 2**x.                                  
;             It does this by using the algebraic identity:   
;                                                             
;             2**x = 2**int(x) * 2**frac(x).                  
;             We can easily compute 2**int(x) with fscale and 
;             2**frac(x) using f2xm1.                         
;                                                             
;             This routine requires three free registers.     


            .code
math_twoTox proc
SaveCW      textequ <[rsp+0]>
MaskedCW    textequ <[rsp+2]>

            sub     rsp, 8  ;Room for local vars
                    
            fstcw   SaveCW

; Modify the control word to truncate when rounding.

            fstcw   MaskedCW
            or      byte ptr MaskedCW[1], 1100b
            fldcw   MaskedCW

            fld     st(0)   ;Duplicate tos.
            frndint         ;Compute integer portion.

            fxch            ;Swap whole and int values.
            fsub    st(0), st(1) ;Compute frac part.

            f2xm1           ;Compute 2**frac(x)-1.

            fld1
            faddp           ;Compute 2**frac(x).

            fxch            ;Get integer portion.
            fld1            ;Compute 1*2**int(x).

            fscale
            fstp    st(1)   ;Remove st(1) (which is 1).
                             
            fmulp           ;2**int(x) * 2**frac(x).

            fldcw   SaveCW  ;Restore rounding mode.
            add     rsp, 8  ;Remove local vars
            ret
math_twoTox endp



; exp(x)- Computes e**x.                              
;         This routine requires three free registers. 
;                                                     
;           exp(x) = 2**(x * lg(e))                  

math_exp    proc
            fldl2e          ;Put lg(e) onto the stack.
            fmulp           ;Compute x*lg(e).
            call    math_twoTox ;Compute 2**(x * lg(e))
            ret
math_exp    endp


;  TenToX(x)- Computes 10**x.                             
;                                                         
;             This routine requires three free registers. 
;                                                         
;           TenToX(x) = 2**(x * lg(10))                  

math_tenTox proc
            fldl2t          ; Put lg(10) onto the stack
            fmulp           ; Compute x*lg(10)
            call    math_twoTox ;Compute 2**(x * lg(10)).
            ret
math_tenTox endp



; YtoX(y,x)- Computes y**x (y=st(1), x=st(0)).           
;            This routine requires three free registers. 
;                                                        
;           Y must be greater than zero.                 
;                                                        
; YtoX(y,x) = 2 ** (x * lg(y))                           


math_yTox   proc

; Note: y = st1, x=st0.
            
            fxch            ;Compute lg(y).
            fld1 
            fxch 
            fyl2x 

            fmulp           ;Compute x*lg(y).
            call    math_twoTox ;Compute 2**(x*lg(y)).
            ret
math_yTox   endp

            end