Code: Select all
Procedure.d Exp(x.d) ; AKJ 03-Jan-09
; Returns e^x where e = 2.718281828459...
;
; Theory: Suppose e^x can be written as 2^N * 2^t
; where N is an integer and t is real (but small).
; Then 2^N would be easy to evaluate and 2^t can be found
; using the ASM instruction F2XM1 provided -1<=t<=+1 .
;
; The problem is to determine N and t.
; To do this take logs to base 2 of the equation e^x = 2^N*2^t :
; LHS = log2(e^x) = loge(e^x)/loge(2) = x/loge(2) = x*log2(e)
; RHS = log2(2^N*2^t) = N + t
; Thus N can be chosen as the nearest integer to x*log2(e)
; whence t will be x*log2(e) - N (therefore between -1 .. +1)
;
; This routine determines N and t by the above method and
; then computes 2^N * 2^t to give the desired result.
;
; Actually a trick (the FSCALE instruction) is used to
; provide a quick and accurate way to do this last step.
; In ASM terminology, FSCALE computes ST0 * 2^Int(ST1)
; which is ideal if ST0 = 2^t and ST1 = N .
;
Protected control.w=$037F ; FPU control word default value
EnableASM
fldcw word [p.v_control] ; Ensure rounding is 'to the nearest'
fld qword [p.v_x] ; st0 = x
fldl2e ; st0 = log2(e) st1 = x
fmulp ; st0 = x*log2(e) = z (say)
fld st0 ; st0 = z st1 = z
frndint ; st0 = N st1 = z
fsub st1, st0 ; st0 = N st1 = t
fxch ; st0 = t st1 = N
f2xm1 ; st0 = 2^t-1 st1 = N
fld1 ; st0 = 1 st1 = 2^t-1 st2 = N
faddp ; st0 = 2^t st1 = N (ideal)
fscale ; st0 = e^x st1 = N
ffree st1
DisableASM
ProcedureReturn ; st0
EndProcedure
; Examples:
Debug Exp(0) ; 1.0
Debug Exp(1) ; 2.7182818284590451
Debug Exp(#PI) ; 23.140692632779267
Debug Exp(43.29) ; 6318414624313423900.0
Debug Exp(-2.6) ; 0.074273578214333877
to avoid unwanted side effects when Exp() is called many times