home *** CD-ROM | disk | FTP | other *** search
-
- ; *******************************************************
- ; * *
- ; * Turbo Pascal Runtime Library Version 7.0 *
- ; * Real Exponentiation *
- ; * *
- ; * Copyright (C) 1989-1993 Norbert Juffa *
- ; * *
- ; *******************************************************
-
- TITLE FPEXP
-
-
- CODE SEGMENT BYTE PUBLIC
-
- ASSUME CS:CODE
-
- ; Externals
-
- EXTRN RealAdd:NEAR,RealSub:NEAR,RealMul:NEAR,RealFloat:NEAR
- EXTRN RealTrunc:NEAR,RealSqr:NEAR,RealDivRev:NEAR
- EXTRN RealMulNoChk:NEAR,RealReduceMP:NEAR,ROverflow:NEAR
- EXTRN RealMulF:NEAR,RealMulFNoChk:NEAR
-
-
- ; Publics
-
- PUBLIC RExp
-
- IFDEF EXTENSIONS
- PUBLIC RPower2,RPower10
- ENDIF
-
- ;-------------------------------------------------------------------------------
- ; Routines RExp, RPower2, and RPower10 exponentiate their argument x to base e,
- ; base 2, and base 10, respectively. All routines do the exponentiation of an
- ; argument x by calculating e^g * 2^n, where g is in -0.5*ln(2)..0.5*ln(2).
- ; While 2^n is a simple scaling operation, e^g is computed using a rational
- ; approximation of the Pade type. The computation of i and g differs for the
- ; three functions. For RPower2, n is computed as n = Round (x), and g as g =
- ; (x - n) * ln (2). For RExp, the computation proceeds as follows: n = Round
- ; (x/ln(2)), g = x - ln(2)*n, where ln(2) is represented by two constants c1
- ; and c2 that provide more than 40 bits of precision, so that the actual
- ; computation becomes x - c1*n - c2*n. This way, loss of accuracy due to the
- ; argument reduction is prevented. The computation of RPower10 is similar to
- ; that of the RExp function n = Round (x/log10(2)), g = x - log10(2) * n by
- ; the multiple precision process described above. Finally, g = g * ln(10).
- ; Actually, these different argument reduction schemes are all derived from
- ; the same process by elimination of unnecessary steps: n = Round (x/logB (2)),
- ; g = (x - n*logB(2)) * ln (B), where B is the base for exponentation.
- ;
- ; If the result of the exponentiation routines underflows the floating point
- ; format, zero is returned. If the computation results in overflow, error 205
- ; is returned through the error handler.
- ;
- ; GPZ := (2.001347076967e1*g^2+8.408086858319e2)*g
- ; QZ := (g^2+1.801617224813e2)*g^2+1.681617371664e3
- ;
- ; e^g := 2 * (0.5 + GPZ / (QZ - GPZ))
- ;
- ; This approximation has a theoretical maximum relative error of 2.98e-14.
- ; Maximum observed error when evaluated in REAL arithmetic is 1.74e-12.
- ;
- ; INPUT: DX:BX:AX argument
- ;
- ; OUTPUT: DX:BX:AX 2^argument, e^argument, 10^argument depending on function
- ;
- ; DESTROYS: AX,BX,CX,DX,SI,DI,Flags
- ;-------------------------------------------------------------------------------
-
- IFDEF EXTENSIONS
-
- RPower10 PROC FAR
- PUSH BP ; save caller's framepointer
- MOV BP,OFFSET Pow10Cst; address table of constants for pow10
- JMP $power_10 ; compute power of ten
- Pow10Cst DW 0007Fh, 09A84h, 09A20h ; log(2)-eps = 3.010299955495e-1
- DW 0005Fh, 0F799h, 0FBCFh ; eps = 1.145110089921e-10
- DW 0CD82h, 0784Bh, 0549Ah ; 1/log(2) = 3.321928094887e+0
- DW 0AB82h, 08DDDh, 0135Dh ; ln (10) = 2.302585092994e+0
- RPower10 ENDP
-
- ALIGN 4
-
- RPower2 PROC FAR
- PUSH BP ; save caller's framepointer
- MOV BP, OFFSET Pow2Cst-18;
- PUSH AX ; save
- MOV SI, BX ; x
- MOV DI, DX ; ditto
- MOV CH, 0FFh ; signal rounding desired
- CALL RealTrunc ; compute n := round (x)
- POP CX ; removed saved word
- CMP CL, 88h ; abs (x) < 128 ?
- JNB $argumnt_err ; no, overflow or underflow
- PUSH AX ; save n
- PUSH CX ; save lsw of x
- CALL RealFloat ; compute float(n)
- POP CX ; restore x to DI:SI:CX
- XOR DH, 80h ; -n
- CALL RealAdd ; compute t := -n + x = n - x
- JMP $power_2 ; compute power of two
-
- Pow2Cst DW 0D280h, 017F7h, 03172h ; ln (2) = 6.931471805599e-1
-
- RPower2 ENDP
-
- ENDIF
-
-
- RExp_Ext PROC FAR
- $argumnt_err:POP BP ; restore caller's frame pointer
- OR DI, DI ; argument negative ?
- JS $exp_zero ; yes, result = 0 to machine precision
- JMP $exp_overfl ; no, overflow, signal error
- $exp_zero: XOR AX, AX ; load
- MOV BX, AX ; a
- CWD ; zero
- RET ; done
- RExp_Ext ENDP
-
- ALIGN 4
-
- RExp PROC FAR
- PUSH BP ; save frame pointer
- MOV BP, OFFSET PowECst; pointer to table of constants
- $power_10: PUSH DX ; save
- PUSH BX ; argument x
- PUSH AX ; on stack
- MOV CX, CS:[BP+12] ; load
- MOV SI, CS:[BP+14] ; constant
- MOV DI, CS:[BP+16] ; 1/lg(2)
- CALL RealMulFNoChk ; compute y := x/lg(2) (DI:SI:CX <> 0)
- POP CX ; get
- POP SI ; back
- POP DI ; x
- CMP AL, 88h ; abs (y) < 128 ?
- JNB $argumnt_err ; no, underflow or overflow
- PUSH CX ; save lsw of x
- MOV CH, -1 ; signal rounding
- CALL RealTrunc ; n = round (y)
- POP CX ; get back lsw of x
- PUSH AX ; save n
- PUSH CX ; save lsw of x
- CALL RealFloat ; convert n to floating-point
- POP CX ; get back lsw of x
- CALL RealReduceMP ; compute t = x - n*c1 - n*c2
-
- IFDEF EXTENSIONS
-
- CMP BP, OFFSET PowECst; function = e^x ?
- JE $approx ; yes, compute approximation with g = t
- $power_2: MOV CX, CS:[BP+18] ; load
- MOV SI, CS:[BP+20] ; constant
- MOV DI, CS:[BP+22] ; 1/lg(2)
- CALL RealMulNoChk ; compute g := t/lg(2) (DI:SI:CX <> 0)
-
- ENDIF
-
- $approx: PUSH DX ; save
- PUSH BX ; g on
- PUSH AX ; stack
- CALL RealSqr ; compute z := g^2
- POP CX ; get
- POP SI ; g from
- POP DI ; stack
- PUSH DX ; save
- PUSH BX ; z on
- PUSH AX ; stack
- PUSH DI ; save
- PUSH SI ; g on
- PUSH CX ; stack
- MOV CX, 01A85h ; load real
- MOV SI, 09690h ; constant
- MOV DI, 0201Bh ; 2.001347076967e1
- CALL RealMulFNoChk ; multiply by z (DI:SI:CX <> 0)
- MOV CX, 0388Ah ; load
- MOV SI, 0C182h ; real constant
- MOV DI, 05233h ; 8.408086858319e2
- CALL RealAdd ; make sum
- POP CX ; get
- POP SI ; g from
- POP DI ; stack
- CALL RealMulF ; compute GPZ
- POP CX ; get
- POP SI ; z from
- POP DI ; stack
- PUSH DX ; save
- PUSH BX ; GPZ
- PUSH AX ; on stack
- MOV AX, 00088h ; load
- MOV BX, 066A5h ; real constant
- MOV DX, 03429h ; 1.801617224813e2
- PUSH DI ; save
- PUSH SI ; z on
- PUSH CX ; stack
- CALL RealAdd ; add z
- POP CX ; get
- POP SI ; z from
- POP DI ; stack
- CALL RealMulF ; multiply result by z
- MOV CX, 0388Bh ; load
- MOV SI, 0C182h ; real constant
- MOV DI, 05233h ; 1.681617371664e3
- CALL RealAdd ; compute QZ
- POP CX ; get
- POP SI ; GPZ from
- POP DI ; stack
- PUSH DI ; save
- PUSH SI ; GPZ on
- PUSH CX ; stack
- CALL RealSub ; compute QZ - GPZ
- POP CX ; get
- POP SI ; GPZ from
- POP DI ; stack
- CALL RealDivRev ; compute GPZ / (QZ-GPZ)
- MOV CX, 80h ; load
- XOR SI, SI ; real constant
- MOV DI, SI ; 0.5
- CALL RealAdd ; compute 0.5 + GPZ / (QZ-GPZ)
- POP CX ; get n
- INC CX ; compute n+1
- ADD AL, CL ; adjust exponent by adding n+1
- POP BP ; restore caller's frame pointer
- JZ $exp_overfl ; overflow error if exponent overflows
- RET ; done
-
- $exp_overfl: JMP ROverflow ; error 205, floating point overflow
-
- PowECst DW 00080h, 017F7h, 0B172h ; ln(2)-eps = 6.931471803691e-1
- DW 00060h, 079ACh, 0D1CFh ; eps = 1.908214929385e-10
- DW 05C81h, 03B29h, 038AAh ; 1/ln(2) = 1.442695040889e+0
-
- RExp ENDP
-
- ALIGN 4
-
- CODE ENDS
-
- END