makefile OBJ=asin.o atan.o exp.o fabs.o floor.o log.o pow.o random.o\ sin.o sinh.o sqrt.o tan.o tanh.o atof.o ftoa.o\ fpst.o frexp.o fsubs.o sqrt87s.o frexp87s.o fsubs87s.o OBJ87=asin87.o atan87.o exp87.o fabs87.o floor87.o log87.o pow87.o random87.o\ exp1087.o sin87.o sinh87.o sqrt87.o tan87.o tanh87.o atof87.o ftoa87.o\ fmod87.o chk87.o frexp87.o isnan.o fpst.o fsubs87.o CC=cc AS=as MODEL= AMODEL=0 .c.o: $(CC) +$(MODEL) -n $*.c -o $@ sqz $@ .asm.o: $(AS) -dMODEL=$(AMODEL) $*.asm -o $@ sqz $@ bld bldlc bldld bldl: $(OBJ) @echo math done bld87 bld87lc bld87ld bld87l: $(OBJ87) @echo math87 done atof87.o: atof.asm $(AS) -dMODEL=$(AMODEL) -dINLINE atof.asm -o $@ sqz $@ ftoa87.o: ftoa.asm $(AS) -dMODEL=$(AMODEL) -dINLINE ftoa.asm -o $@ sqz $@ asin87.o: asin.c $(CC) +$(MODEL) -n +e asin.c -o $@ sqz $@ fabs87.o: fabs.c $(CC) +$(MODEL) -n +e fabs.c -o $@ sqz $@ floor87.o: floor.c $(CC) +$(MODEL) -n +e floor.c -o $@ sqz $@ pow87.o: pow.c $(CC) +$(MODEL) -n +e pow.c -o $@ sqz $@ random87.o: random.c $(CC) +$(MODEL) -n +e random.c -o $@ sqz $@ sinh87.o: sinh.c $(CC) +$(MODEL) -n +e sinh.c -o $@ sqz $@ sqrt87.o: sqrt.c $(CC) +$(MODEL) -n +e sqrt.c -o $@ sqz $@ tanh87.o: tanh.c $(CC) +$(MODEL) -n +e tanh.c -o $@ sqz $@ asin.c #include "math.h" #include "errno.h" static double arcsine(); double asin(x) double x; { return arcsine(x,0); } double acos(x) double x; { return arcsine(x,1); } #define P1 -0.27368494524164255994e+2 #define P2 +0.57208227877891731407e+2 #define P3 -0.39688862997504877339e+2 #define P4 +0.10152522233806463645e+2 #define P5 -0.69674573447350646411 #define Q0 -0.16421096714498560795e+3 #define Q1 +0.41714430248260412556e+3 #define Q2 -0.38186303361750149284e+3 #define Q3 +0.15095270841030604719e+3 #define Q4 -0.23823859153670238830e+2 #define P(g) ((((P5*g P4)*g P3)*g P2)*g P1) #define Q(g) (((((g Q4)*g Q3)*g Q2)*g Q1)*g Q0) static double arcsine(x,flg) double x; { double y, g, r; register int i; extern int errno; static double a[2] = { 0.0, 0.78539816339744830962 }; static double b[2] = { 1.57079632679489661923, 0.78539816339744830962 }; y = fabs(x); i = flg; if (y < 2.3e-10) r = y; else { if (y > 0.5) { i = 1-i; if (y > 1.0) { errno = EDOM; return 0.0; } g = (0.5-y)+0.5; g = ldexp(g,-1); y = sqrt(g); y = -(y+y); } else g = y*y; r = y + y* ((P(g)*g) /Q(g)); } if (flg) { if (x < 0.0) r = (b[i] + r) + b[i]; else r = (a[i] - r) + a[i]; } else { r = (a[i] + r) + a[i]; if (x < 0.0) r = -r; } return r; } atan.c #include "math.h" #include "errno.h" #ifdef MPU8086 #define MAXEXP 1024 #define MINEXP -1023 #else #define MAXEXP 504 #define MINEXP -512 #endif #define PI 3.14159265358979323846 #define PIov2 1.57079632679489661923 double atan2(v,u) double u,v; { double f, frexp(); int vexp, uexp; extern int flterr; extern int errno; if (u == 0.0) { if (v == 0.0) { errno = EDOM; return 0.0; } else if (v > 0.0 ) return PIov2; return -PIov2; } frexp(v, &vexp); frexp(u, &uexp); if (vexp-uexp > MAXEXP-3) /* overflow */ f = PIov2; else { if (vexp-uexp < MINEXP+3) /* underflow */ f = 0.0; else f = atan(fabs(v/u)); if (u < 0.0) f = PI - f; } if (v < 0.0) f = -f; return f; } #define P0 -0.13688768894191926929e+2 #define P1 -0.20505855195861651981e+2 #define P2 -0.84946240351320683534e+1 #define P3 -0.83758299368150059274e+0 #define Q0 +0.41066306682575781263e+2 #define Q1 +0.86157349597130242515e+2 #define Q2 +0.59578436142597344465e+2 #define Q3 +0.15024001160028576121e+2 #define P(g) (((P3*g P2)*g P1)*g P0) #define Q(g) ((((g Q3)*g Q2)*g Q1)*g Q0) double atan(x) double x; { double f, r, g; int n; static double Avals[4] = { 0.0, 0.52359877559829887308, 1.57079632679489661923, 1.04719755119659774615 }; n = 0; f = fabs(x); if (f > 1.0) { f = 1.0/f; n = 2; } if (f > 0.26794919243112270647) { f = (((0.73205080756887729353*f - 0.5) - 0.5) + f) / (1.73205080756887729353 + f); ++n; } if (fabs(f) < 2.3e-10) r = f; else { g = f*f; r = f + f * ((P(g)*g) /Q(g)); } if (n > 1) r = -r; r += Avals[n]; if (x < 0.0) r = -r; return r; } atan87.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h EDOM equ 22 dataseg segment public byte 'data' extrn errno_:word ifdef STATRES result db 8 dup (?) endif dataseg ends assume cs:codeseg,ds:dataseg ;double atan(x) ;double x; procdef atan,<> sub sp,2 fld qword ptr xx ;load x ftst ; see if x is negative fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor bx,bx sahf ja skip3 fchs ; make it positive mov bx,1 ; but remember the sign skip3: fld1 ; load a one fcomp ; x should be < 1.0 fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor cx,cx sahf ja skip4 mov cx,1 fld1 ;load a one fdivr ; x = 1.0 / x skip4: fld1 fpatan ; compute the arctan test cx,1 jz skip1 mov word ptr -2[bp],-1 fild word ptr -2[bp] fldpi ; load pi fscale ;compute pi / 2 fxch ;get scale factor back on top fstp st(0) ;and discard fsubr ; x = pi/2 - x skip1: test bx,1 jz nosign fchs nosign: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif endif fwait add sp,2 pret pend atan procdef atan2,<,> sub sp,2 fld qword ptr y ;load y ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnz ok1 ; ; y is zero, if x is zero also, error ; fld qword ptr x ;load x ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnz okx mov errno_,EDOM zerores: fstp st(0) ;clear stack fstp st(0) fldz ;answer is zero jmp exit okx: mov bx,0 ja notneg ; x < 0 mov bx,1 notneg: fstp st(0) fstp st(0) ; answer is +/- pi/2 mov word ptr -2[bp],-1 fild word ptr -2[bp] fldpi fscale fxch fstp st(0) test bx,1 jz oksign fchs oksign: jmp exit ok1: ; ; x and y are both non zero, but x must be < y ; mov bx,word ptr x+6 xor bx,word ptr y+6 fabs ; y = fabs(y) fld qword ptr x fabs ; x = fabs(x) fxch fcom st(1) fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor cx,cx sahf jz zerores ja nodiv fxch mov cx,1 nodiv: fpatan ; compute the arctangent test cx,cx jz noadjust mov word ptr -2[bp],-1 fild word ptr -2[bp] fldpi fscale fxch fstp st(0) fsubr ; res = pi/2 - res noadjust: test bx,8000h ; should result be negative jz notnegr fchs notnegr: test word ptr y+6,8000h ; y < 0 ? jz exit test word ptr x+6,8000h ; x < 0 too? jz addpi fldpi fsub ; x -= pi jmp exit addpi: fldpi fadd exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif endif fwait add sp,2 pret pend atan2 finish end atof.asm ; Copyright Manx Software Systems, Inc. 1983-1987. All rights reserved. ; ;double ;atof(cp) ;register char *cp; include lmacros.h IFDEF LONGPTR cp equ es:byte ptr [di] getes macro mov es,ss:word ptr acp[2] endm ELSE cp equ byte ptr [di] getes macro ; endm ENDIF zero dw 0,0,0,0 ten dw 0,0,0,4024h ifdef STATRES dataseg segment public word 'data' result db 8 dup (?) dataseg ends assume ds:dataseg endif procdef atof,<> sub sp,4 push di push si ;{ ifndef LONGPTR mov di,ds mov es,di endif ldptr di,acp,es ; double acc; ; int msign, esign, dpflg; ; int i, dexp; msign equ byte ptr -1[bp] esign equ byte ptr -2[bp] ;these two aren't active at the same time dpflg equ byte ptr -2[bp] temp equ word ptr -4[bp] ; while (*cp == ' ' || *cp == '\t') ; ++cp; skiploop: mov al,cp cmp al,' ' je skipbl cmp al,9 jne skipdone skipbl: inc di jmp skiploop skipdone: ; if (*cp == '-') { cmp al,45 jne $3 ; ++cp; inc di ; msign = 1; mov msign,1 jmp short $4 ; } else { $3: ; msign = 0; mov msign,0 ; if (*cp == '+') ; ++cp; cmp al,43 jne $4 inc di ; } $4: ; dpflg = dexp = 0; mov si,0 mov dpflg,0 ; for (acc = zero ; ; ++cp) { ifdef INLINE fldz else mov bx, offset zero call $dldpcs endif $6: ; if (isdigit(*cp)) { getes mov al,cp cmp al,'0' jb $9 cmp al,'9' ja $9 ; acc *= ten; ifdef INLINE fmul cs:qword ptr ten else mov bx, offset ten call $dldscs call $dml endif ; acc += *cp - '0'; ifndef INLINE call $dswap endif getes mov al,cp cbw add ax,-48 ifdef INLINE mov temp,ax fild temp fadd else call $itod call $dad endif ; if (dpflg) ; --dexp; cmp dpflg,0 je $11 dec si jmp short $11 ; } else if (*cp == '.') { $9: cmp al,'.' jne $8 ; if (dpflg) ; break; cmp dpflg,0 jne $8 ; dpflg = 1; mov dpflg,1 ; } else ; break; $11: ; } inc di jmp $6 $8: ; if (*cp == 'e' || *cp == 'E') { cmp al,101 je $15 cmp al,69 jne $14 $15: ; ++cp; inc di ; if (*cp == '-') { cmp cp,45 jne $16 ; ++cp; inc di ; esign = 1; mov esign,1 jmp short $17 ; } else { $16: ; esign = 0; mov esign,0 ; if (*cp == '+') ; ++cp; cmp cp,43 jne $17 inc di ; } $17: ; for ( i = 0 ; isdigit(*cp) ; i = i*10 + *cp++ - '0' ) sub ax,ax mov cx,10 jmp short $20 $19: mul cx mov dx,ax mov al,cp inc di cbw add ax,dx add ax,-48 $20: mov bl,cp cmp bl,'0' jb $21 cmp bl,'9' jbe $19 ; ; $21: ; if (esign) ; i = -i; cmp esign,0 je $22 neg ax $22: ; dexp += i; add si,ax ; } ; if (dexp < 0) { $14: ifndef INLINE mov bx, offset ten call $dldscs endif test si,si jns $23 ; while (dexp++) $24: ; acc /= ten; ifdef INLINE fdiv cs:qword ptr ten else call $ddv endif inc si jnz $24 jmp short $26 ; } else if (dexp > 0) { $23: jz $26 ; while (dexp--) $28: ; acc *= ten; ifdef INLINE fmul cs:qword ptr ten else call $dml endif dec si jnz $28 ; } $26: ; if (msign) ; acc = -acc; cmp msign,0 je $30 ifdef INLINE fchs else call $dng endif ; return acc; $30: ifdef STATRES ifdef INLINE fstp qword ptr result else mov bx,offset result call $dstds endif mov ax,offset result mov dx,ds endif pop si pop di mov sp,bp pret ;} pend atof ifndef INLINE ifdef FARPROC extrn $dad:far,$dml:far,$ddv:far extrn $dng:far,$dswap:far,$itod:far extrn $dldpcs:far,$dldscs:far,$dstds:far else extrn $dad:near,$dml:near,$ddv:near extrn $dng:near,$dswap:near,$itod:near extrn $dldpcs:near,$dldscs:near,$dstds:near endif endif finish end chk87.asm ;Copyright (C) Manx Software Systems, Inc. 1987. All rights reserved. ; :ts=8 include lmacros.h dataseg segment word public 'data' public chop_ctl, round_ctl, rdown_ctl chop_ctl dw 0fbfH ;control word for Chop mode round_ctl dw 03bfH ;control word for Round nearest mode rdown_ctl dw 07bfh ;control word for Round Down mode mess db "8087/80287 is absent or not functional!" db 10 ; newline MESSLEN equ 40 dataseg ends public $maxdigit ; this must be in CODESEG $maxdigit dw 16 ;maximum # of digits for ftoa() to produce. assume ds:dataseg public _chk87_, $fltinit $fltinit proc _chk87_: push bp mov bp,sp sub sp,2 fninit fnstcw word ptr -2[bp] mov cx,50 w1loop: loop w1loop ; wait for a while and word ptr -2[bp],01f3fh ; clear unused bits cmp word ptr -2[bp],0033fh ; is 8087 there? jnz notthere ; no, return error to caller fstsw word ptr -2[bp] mov cx,50 w2loop: loop w2loop ; wait for a while test word ptr -2[bp],0b8bfh ; all status bits should be off jz ok_8087 ; 8087 is there!! notthere: stc ;bad status, no 8087 present jmp short exit ok_8087: ;note: the carry is cleared by the test instr. above fldcw word ptr round_ctl ;set initial control exit: mov sp,bp pop bp ret $fltinit endp finish end exp.c #include "math.h" #include "errno.h" #define P0 0.25000000000000000000e+0 #define P1 0.75753180159422776666e-2 #define P2 0.31555192765684646356e-4 #define Q0 0.50000000000000000000e+0 #define Q1 0.56817302698551221787e-1 #define Q2 0.63121894374398503557e-3 #define Q3 0.75104028399870046114e-6 #define P(z) ((P2*z + P1)*z + P0) #define Q(z) (((Q3*z + Q2)*z + Q1)*z + Q0) #define EPS 2.710505e-20 double exp(x) double x; { int n; double xn, g, r, z; extern int errno; if (x > LOGHUGE) { errno = ERANGE; return HUGE_VAL; } if (x < LOGTINY) { errno = ERANGE; return 0.0; } if (fabs(x) < EPS) return 1.0; n = z = x * 1.4426950408889634074; if (n < 0) --n; if (z-n >= 0.5) ++n; xn = n; g = ((x - xn*0.693359375)) + xn*2.1219444005469058277e-4; z = g*g; r = P(z)*g; r = 0.5 + r/(Q(z)-r); return ldexp(r,n+1); } exp1087.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h log10e db 016h,055h,0b5h,0bbh,0b1h,06bh,02h,040h ifdef FARPROC extrn exp_:far else extrn exp_:near endif assume cs:codeseg,ds:dataseg ;double exp10 (x) ;double x; procdef exp10,<> fld qword ptr x fmul cs:qword ptr log10e sub sp,8 mov bx,sp fstp ss:qword ptr [bx] fwait call exp_ add sp,8 pret pend exp10 finish end exp87.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h ERANGE equ 21 dataseg segment para public 'data' extrn errno_:word,chop_ctl:word,round_ctl:word ifdef STATRES result db 8 dup (?) endif dataseg ends assume cs:codeseg,ds:dataseg huge db 020H,062H,010H,058H,039H,02EH,086H,040H tiny db 080H,049H,0CH,02H,02BH,023H,086H,0C0H plus5 db 00H,00H,00H,00H,00H,00H,0E0H,03FH ; +0.5 minus5 db 00H,00H,00H,00H,00H,00H,0E0H,0BFH ; -0.5 ;double exp(x) ;double x; procdef exp,<> sub sp,6 fld qword ptr x ; load input value fcom cs:qword ptr huge ; must be less than or equal to LOGHUGE fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf ja badval fcom cs:qword ptr tiny ; must be >= LOGTINY fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jae goodval badval: mov errno_,ERANGE ; range error fstp st(0) ; get rid of original number fldz ; result is zero jmp exit goodval: fldln2 ; load log(e) 2 fdiv ; x = x / (log(e) 2) fld st(0) ; make a copy of x/(log(e) 2 ftst ; check for number < 0 fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf mov bx,offset plus5 ;default rounding is +0.5 jnc roundup mov bx,offset minus5 ;otherwise -0.5 roundup: fadd cs:qword ptr [bx] ;add round fldcw word ptr chop_ctl fistp word ptr -6[bp] ; n = x + (x < 0)?-0.5:0.5 fldcw word ptr round_ctl fild word ptr -6[bp] ; reload n fsub ; x = x - n mov word ptr -4[bp],0 ; flag = 0 ftst ; x < 0 fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnc notneg fchs ; x = -x mov word ptr -4[bp],1 ;flag = 1; notneg: f2xm1 ; x = 2**x - 1 fld1 ; load one fadd ; x = x + 1 (i.e. 2**x) cmp word ptr -4[bp],0 ; if (flag) je noinvert fld1 ; load one fdivr ; x = 1.0/x noinvert: fild word ptr -6[bp] ; reload n fxch ; get x back on top fscale ; x = x * 2**n fxch ; get n back on top fstp st(0) ; and discard it (this keeps stack clean) exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,6 pret pend exp finish end fabs.c #ifdef MPU68K #define SIGN 0 #else #define SIGN 7 #endif double fabs(dou) double dou; { register char *cp; cp = (char *)&dou; cp[SIGN] &= 0x7f; return dou; } floor.c #include "math.h" double floor(d) double d; { if (d < 0.0) return -ceil(-d); modf(d, &d); return d; } double ceil(d) double d; { if (d < 0.0) return -floor(-d); if (modf(d, &d) > 0.0) ++d; return d; } fmod87.asm ; Copyright Manx Software Systems, Inc. 1983, 1987 ; :ts=8 include lmacros.h dataseg segment word public 'data' ifdef STATRES result db 8 dup (?) endif dataseg ends assume ds:dataseg procdef fmod, <,> ; ; double fmod(doud,denom) ; sub sp,2 fld qword ptr denom ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnz divok fstp st(0) fld qword ptr doub jmp exit divok: fabs fld qword ptr doub ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor bx,bx sahf jnc notneg mov bx,1 fabs notneg: fprem ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jz done fcom st(1) fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf ja notneg done: fxch fstp st(0) test bx,bx jz exit fchs exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend fmod finish end fpst.asm ; Copyright (C) 1983 by Manx Software Systems include lmacros.h internal $FPSTI intrdef $fprds ;preinc or predec a single float using ds:bx mov cx,ds mov es,cx jmp short fpr intrdef $fprss ;preinc or predec a single float using ss:bx mov cx,ss mov es,cx jmp short fpr intrdef $fpres ;preinc or predec a single float using es:bx fpr: push bx push es call $itod pop es pop bx push bx push es call $fldses call $dad pop es pop bx call $fstes ret intrdef $fpsds ;postinc or postdec a single float using ds:bx mov cx,ds mov es,cx jmp short fps intrdef $fpsss ;postinc or postdec a single float using ss:bx mov cx,ss mov es,cx jmp short fps intrdef $fpses ;postinc or postdec a single float using es:bx fps: push bx push es call $itod pop es pop bx push bx push es call $fldses call $dswap call $dpsh call $dad call $dpop pop es pop bx call $fstes call $dswap ret intrdef $dprds ;preinc or predec a double float using ds:bx mov cx,ds mov es,cx jmp short dpr intrdef $dprss ;preinc or predec a double float using ss:bx mov cx,ss mov es,cx jmp short dpr intrdef $dpres ;preinc or predec a double float using es:bx dpr: push bx push es call $itod pop es pop bx push bx push es call $dldses call $dad pop es pop bx call $dstes ret intrdef $dpsds ;postinc or postdec a double float using ds:bx mov cx,ds mov es,cx jmp short dps intrdef $dpsss ;postinc or postdec a double float using ss:bx mov cx,ss mov es,cx jmp short dps intrdef $dpses ;postinc or postdec a double float using es:bx dps: push bx push es call $itod pop es pop bx push bx push es call $dldses call $dswap call $dpsh call $dad call $dpop pop es pop bx call $dstes call $dswap ret ; ifdef FARPROC extrn $itod:far,$dad:far,$dpsh:far,$dpop:far,$dswap:far extrn $fldses:far,$fstes:far,$dldses:far,$dstes:far else extrn $itod:near,$dad:near,$dpsh:near,$dpop:near,$dswap:near extrn $fldses:near,$fstes:near,$dldses:near,$dstes:near endif $FPSTI endp finish end frexp.asm ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 ; the psuedo accumlators are formated as follows: ; -10 -8 -6 -4 -2 0 ; |grd + LS ----- fraction ---- MS | exp | sign ; ; floating point system error codes: UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; include lmacros.h dataseg segment word public 'data' dw 5 dup (?) temp dw ? extrn flprm:word,flsec:word extrn flterr_:word dataseg ends assume ds:dataseg ifdef FARPROC extrn $dldpss:far, $dst:far, $itod:far extrn $dad:far, $dsb:far, $isnan:far else extrn $dldpss:near, $dst:near, $itod:near extrn $dad:near, $dsb:near, $isnan:near endif procdef _isnan,<> lea bx,word ptr ddd ;compute address of first argument call $dldpss ;load it into the float primary call $isnan pret pend _isnan procdef frexp, <,> ; ; frexp(d, &i) ; returns 0 <= x < 1 ; such that: d = x * 2^i lea bx,word ptr d ;compute address of first argument call $dldpss ;load it into the float primary mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jnz fr_nzero ldptr bx,i,es ;get pointer ifndef LONGPTR mov ds:word ptr [bx],0 else mov es:word ptr [bx],0 endif pret fr_nzero: sub ax,1022 mov word ptr -2[bx],1022 ldptr bx,i,es ;get pointer ifndef LONGPTR mov ds:word ptr [bx],ax else mov es:word ptr [bx],ax endif pret pend frexp ; ; ldexp(d, i) ; returns x = d * 2^i procdef ldexp, <,> lea bx,word ptr dou ;compute address of first argument call $dldpss ;load it into the float primary mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jz ld_zero add ax,ii ;add i to exponent js ld_underflow cmp ax,2048 jl ld_ret mov flterr_,UNDER_FLOW mov ax,2047 ld_ret: mov word ptr -2[bx],ax ld_zero: pret ; ld_underflow: mov flterr_,UNDER_FLOW sub ax,ax jmp ld_ret pend ldexp ; ; modf(d, dptr) ; returns fractional part of d, and ; stores integral part into *dptr procdef modf,<,> push di push si push ds lea bx,word ptr doubl ;compute address of first argument call $dldpss ;load it into the float primary std mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jnz mf_nzero ldptr bx,dptr,es ;get pointer call $dst mf_return: cld pop ds pop si pop di pret mf_nzero: mov di,ds mov es,di mov si,bx mov di,offset temp mov cx,6 ;save value for fraction part later rep movsw sub ax,1023 jns int_notzero mov ax,0 call $itod jmp get_fraction int_notzero: cmp ax,52 jna mf_frac ;fraction is zero ldptr bx,dptr,es ;get pointer call $dst ;store integer part away sub ax,ax call $itod jmp mf_return mf_frac: sub di,di mov cx,ax mov ax,4 mf_count: sub cx,ax jbe mf_cdone dec di mov ax,8 jmp mf_count mf_cdone: jcxz no_shift neg cx mov al,byte ptr -3[bx][di] shr al,cl shl al,cl mov byte ptr -3[bx][di],al no_shift: dec di zap_loop: cmp di,-8 jle get_fraction mov byte ptr -3[bx][di],0 dec di jmp zap_loop get_fraction: ldptr bx,dptr,es ;get pointer call $dst ;store integer part away std pop ds push ds mov di,flprm xchg di,flsec mov flprm,di mov si,ds mov es,si mov si,offset temp mov cx,6 ;restore original value rep movsw call $dsb ;compute fractional part jmp mf_return pend modf finish end frexp87.asm ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 ; ; floating point system error codes: UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; include lmacros.h dataseg segment word public 'data' status dw ? result db 8 dup (?) extrn chop_ctl:word, round_ctl:word dataseg ends assume ds:dataseg procdef frexp,<,> ; ; frexp(d, &i) ; returns 0 <= x < 1 ; such that: d = x * 2^i fld1 fchs fld qword ptr d ftst fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jz zero fxtract fxch fsub st,st(2) ldptr bx,i,es ifdef LONGPTR fistp es:word ptr [bx] else fistp word ptr [bx] endif fscale fxch fstp st(0) ifdef STATRES jmp exit else pret endif zero: ldptr bx,i,es ifdef LONGPTR mov es:word ptr [bx],0 else mov word ptr [bx],0 endif fstp st(0) fstp st(0) fldz ifdef STATRES exit: fstp qword ptr result fwait mov ax,offset result ifdef LONGPTR mov dx,ds endif endif pret pend frexp ; ; ldexp(d, i) ; returns x = d * 2^i procdef ldexp, <,> fild word ptr ii fld qword ptr dou fscale fxch fstp st(0) ifdef STATRES fstp qword ptr result fwait mov ax,offset result ifdef LONGPTR mov dx,ds endif endif pret pend ldexp ; ; modf(d, dptr) ; returns fractional part of d, and ; stores integral part into *dptr procdef modf, <,> fld qword ptr doub fld st(0) fldcw word ptr chop_ctl frndint fldcw word ptr round_ctl ldptr bx,dptr,es ifdef LONGPTR fst es:qword ptr [bx] else fst qword ptr [bx] endif fsub ifdef STATRES fstp qword ptr result fwait mov ax,offset result ifdef LONGPTR mov dx,ds endif endif pret pend modf finish end frexp87s.asm ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 ; the psuedo accumlators are formated as follows: ; -10 -8 -6 -4 -2 0 ; |grd + LS ----- fraction ---- MS | exp | sign ; ; floating point system error codes: UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; include lmacros.h dataseg segment word public 'data' dw 5 dup (?) temp dw ? extrn flprm:word,flsec:word extrn flterr_:word status dw ? extrn $flt_inx:word,chop_ctl:word, round_ctl:word dataseg ends assume ds:dataseg ifdef FARPROC extrn $dldpss:far, $dst:far, $itod:far extrn $dad:far, $dsb:far, $isnan:far else extrn $dldpss:near, $dst:near, $itod:near extrn $dad:near, $dsb:near, $isnan:near endif procdef _isnan,<> lea bx,word ptr ddd ;compute address of first argument call $dldpss ;load it into the float primary call $isnan pret pend _isnan procdef frexp, <,> ; ; frexp(d, &i) ; returns 0 <= x < 1 ; such that: d = x * 2^i cmp $flt_inx,0 jnz $frexp87 lea bx,word ptr d ;compute address of first argument call $dldpss ;load it into the float primary mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jnz fr_nzero ldptr bx,i,es ;get pointer ifdef LONGPTR mov es:word ptr [bx],0 else mov ds:word ptr [bx],0 endif pret fr_nzero: sub ax,1022 mov word ptr -2[bx],1022 ldptr bx,i,es ;get pointer ifdef LONGPTR mov es:word ptr [bx],ax else mov ds:word ptr [bx],ax endif pret $frexp87: fld1 fchs fld qword ptr d ftst fstsw status fwait mov ah,byte ptr status+1 sahf je zero fxtract fxch fsub st,st(2) ldptr bx,i,es ifdef LONGPTR fistp es:word ptr [bx] else fistp ds:word ptr [bx] endif fscale fxch fstp st(0) fwait pret zero: fstp st(0) fstp st(0) fldz ldptr bx,i,es ifdef LONGPTR mov es:word ptr [bx],0 else mov ds:word ptr [bx],0 endif pret pend frexp ; ; ldexp(d, i) ; returns x = d * 2^i procdef ldexp, <,> cmp $flt_inx,0 jnz $ldexp87 lea bx,word ptr dou ;compute address of first argument call $dldpss ;load it into the float primary mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jz ld_zero add ax,ii ;add i to exponent js ld_underflow cmp ax,2048 jl ld_ret mov flterr_,UNDER_FLOW mov ax,2047 ld_ret: mov word ptr -2[bx],ax ld_zero: pret ; ld_underflow: mov flterr_,UNDER_FLOW sub ax,ax jmp ld_ret $ldexp87: fild word ptr ii fld qword ptr dou fscale fxch fstp st(0) pret pend ldexp ; ; modf(d, dptr) ; returns fractional part of d, and ; stores integral part into *dptr procdef modf,<,> cmp $flt_inx,0 jz modf_soft fld qword ptr doubl fld st(0) fldcw chop_ctl frndint ldptr bx,dptr,es fldcw round_ctl ifdef LONGPTR fst es:qword ptr [bx] else fst ds:qword ptr [bx] endif fsub pret modf_soft: push di push si push ds lea bx,word ptr doubl ;compute address of first argument call $dldpss ;load it into the float primary std mov bx,flprm mov ax,word ptr -2[bx] ;fetch current exponent value test ax,ax jnz mf_nzero ldptr bx,dptr,es ;get pointer call $dst mf_return: cld pop ds pop si pop di pret mf_nzero: mov di,ds mov es,di mov si,bx mov di,offset temp mov cx,6 ;save value for fraction part later rep movsw sub ax,1023 jns int_notzero mov ax,0 call $itod jmp get_fraction int_notzero: cmp ax,52 jna mf_frac ;fraction is zero ldptr bx,dptr,es ;get pointer call $dst ;store integer part away sub ax,ax call $itod jmp mf_return mf_frac: sub di,di mov cx,ax mov ax,4 mf_count: sub cx,ax jbe mf_cdone dec di mov ax,8 jmp mf_count mf_cdone: jcxz no_shift neg cx mov al,byte ptr -3[bx][di] shr al,cl shl al,cl mov byte ptr -3[bx][di],al no_shift: dec di zap_loop: cmp di,-8 jle get_fraction mov byte ptr -3[bx][di],0 dec di jmp zap_loop get_fraction: ldptr bx,dptr,es ;get pointer call $dst ;store integer part away std pop ds push ds mov di,flprm xchg di,flsec mov flprm,di mov si,ds mov es,si mov si,offset temp mov cx,6 ;restore original value rep movsw call $dsb ;compute fractional part jmp mf_return pend modf finish end fsubs.asm ifndef INTERNAL ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 ; the psuedo accumlators are formated as follows: ; -12 -10 -8 -6 -4 -2 0 ; |guard digits + LS ----- fraction ---- MS | exp | sign ; ; floating point system error codes: include lmacros.h UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; dataseg segment word public 'data' public flprm,flsec public flterr_ flterr_ dw 0 flprm dw acc1 flsec dw acc2 YU dw ? VEE dw ? dw 5 dup (?) acc1 dw 7 dup (?) acc2 dw ? ; ;work area for divide and multiply routines ; dw 4 dup (?) temp dw 4 dup (?) loop_count db 0 ;iterations left (for divide) lcnt1 db 0 ;# iter. for this word of quotient dataseg ends assume ds:dataseg internal $floats endif public $maxdigit ; this must be in CODESEG $maxdigit dw 16 ;maximum # of digits for ftoa() to produce. intrdef $isnan sub ax,ax ret intrdef $fldpds ;load single float into primary accum using ds:bx ifndef LONGPTR intrdef $fldp endif push di mov di,ds mov es,di mov di,flprm jmp short fload intrdef $fldpss ;load single float into primary accum using ss:bx push di mov di,ss mov es,di mov di,flprm jmp short fload intrdef $fldpes ;load single float into primary accum using es:bx ifdef LONGPTR intrdef $fldp endif push di mov di,flprm fload: push si mov ax,es:2[bx] ;get exponent/sign word of number mov byte ptr [di],ah ;save sign mov dh,al ;save fraction bits shl ax,1 ;get LS bit of exponent xchg ah,al and ax,0ffH jnz fld_nz push ds mov ax,ds mov es,ax jmp loadzero fld_nz: sub ax,127 ;adjust from excess 127 notation add ax,1023 ;put into excess 1023 notation mov word ptr -2[di],ax ;and save or dh,80H ;turn "hidden" bit back on mov dl,es:byte ptr 1[bx] mov ah,es:byte ptr [bx] sub al,al shr dx,1 ;shift fraction into same position as a double rcr ax,1 shr dx,1 rcr ax,1 shr dx,1 rcr ax,1 mov word ptr -4[di],dx mov word ptr -6[di],ax sub ax,ax mov word ptr -8[di],ax mov word ptr -10[di],ax mov word ptr -12[di],ax pop si pop di ret intrdef $fldsds ;load single float into secondary accum using ds:bx ifndef LONGPTR intrdef $flds endif push di mov di,ds mov es,di mov di,flsec jmp short fload intrdef $fldsss ;load single float into secondary accum using ss:bx push di mov di,ss mov es,di mov di,flsec jmp short fload intrdef $fldses ;load single float into secondary accum using es:bx ifdef LONGPTR intrdef $flds endif push di mov di,flsec jmp short fload intrdef $fstds ; store single float from primary using ds:bx ifndef LONGPTR intrdef $fst endif mov cx,ds mov es,cx jmp short dofst intrdef $fstss ; store single float from primary using ss:bx mov cx,ss mov es,cx jmp short dofst intrdef $fstes ;store single float from primary using es:bx ifdef LONGPTR intrdef $fst endif dofst: push di push si push bx call dornd pop di mov si,flprm mov ax,-2[si] ;get exponent test ax,ax jnz fst_nzero mov es:word ptr [di],0 mov es:word ptr 2[di],0 pop si pop di ret fst_nzero: sub ax,1023 ;switch from excess 1023 notation add ax,127 ;into excess 127 notation mov dx,-4[si] mov bx,-6[si] add bx,10H ;round number adc dx,0 shl bx,1 ;move number back into proper position rcl dx,1 shl bx,1 rcl dx,1 test dx,dx js fix_exp shl bx,1 rcl dx,1 jmp short fst_merge fix_exp: inc ax ;adjust exponent fst_merge: mov cl,7 shl ax,cl mov cl,[si] ;get sign and cl,80H or ah,cl ;merge sign and exponent and dh,7fH ;clear "hidden" bit or al,dh ;merge with sign/exponent mov es:word ptr 2[di],ax mov es:byte ptr 1[di],dl mov es:byte ptr [di],bh pop si pop di ret ; intrdef $fstsds ; store single float from secondary using ds:bx ifndef LONGPTR intrdef $fsts endif mov cx,ds mov es,cx jmp short dofsts intrdef $fstsss ; store single float fromn secondary using ss:bx mov cx,ss mov es,cx jmp short dofsts intrdef $fstses ; store single float from secondary using es:bx ifdef LONGPTR intrdef $fsts endif dofsts: mov ax,flprm xchg ax,flsec mov flprm,ax ifdef FARPROC call far ptr $fstes else call $fstes endif mov ax,flprm xchg ax,flsec mov flprm,ax ret intrdef $dldpds ; load double float in primary using ds:bxS ifndef LONGPTR intrdef $dldp endif mov cx,ds mov es,cx jmp short dodldp intrdef $dldpss ; load double float in primary using ss:bx mov cx,ss mov es,cx jmp short dodldp intrdef $dldpcs ; load double float in primary using cs:bx ifndef FARPROC mov cx,cs mov es,cx else mov cx,bx mov bx,sp mov bx,ss:2[bx] xchg cx,bx mov es,cx endif jmp short dodldp intrdef $dldpes ;load double float in primary using es:bx ifdef LONGPTR intrdef $dldp endif dodldp: push di mov di,flprm dload: push si lea si,6[bx] dload2: push ds mov cx,es ;swap the segment registers mov dx,ds mov es,dx mov ds,cx std lods word ptr [si];get first two bytes of number mov es:byte ptr [di],ah ;save sign mov dh,al ;save top nibble of fraction mov cl,4 shr ax,cl and ax,7ffH ;isolate exponent jz loadzero sub di,2 stos word ptr [di] and dh,15 ;isolate fraction or dh,10H ;put back "hidden" bit mov es:byte ptr 1[di],dh mov cx,6 inc si rep movs byte ptr [di], byte ptr [si] mov al,0 stosb ;clear guard bytes stosb stosb cld pop ds pop si pop di ret loadzero: std sub ax,ax mov cx,7 rep stos word ptr [di] cld pop ds pop si pop di ret intrdef $dldsds ; load double float in secondary using ds:bx ifndef LONGPTR intrdef $dlds endif mov cx,ds mov es,cx jmp dolds intrdef $dldsss ; load double float in secondary using ss:bx mov cx,ss mov es,cx jmp dolds intrdef $dldscs ; load double float in secondary using cs:bx ifndef FARPROC mov cx,cs mov es,cx else mov cx,bx mov bx,sp mov bx,ss:2[bx] xchg cx,bx mov es,cx endif jmp dolds intrdef $dldses ; load double float in secondary using es:bx ifdef LONGPTR intrdef $dlds endif dolds: push di mov di,flsec jmp short dload intrdef $dstds ; store double float from primary using ds:bx ifndef LONGPTR intrdef $dst endif mov cx,ds mov es,cx jmp short dodst intrdef $dstss ; store double float from primary using ss:bx mov cx,ss mov es,cx jmp short dodst intrdef $dstes ; store double float from primary using es:bx ifdef LONGPTR intrdef $dst endif dodst: std push di push si push bx ;save address call dornd ;round fraction to 7 bytes pop di ;restore address add di,6 mov si,flprm mov dl,[si] ;get sign and dl,80H sub si,2 lods word ptr [si];get exponent mov cl,4 shl ax,cl or ah,dl ;merge sign and exponent mov dl,1[si] and dl,15 ;clear "hidden" bit or al,dl ;merge with sign/exponent stos word ptr [di] mov cx,6 inc di rep movs byte ptr [di], byte ptr [si] cld pop si pop di ret intrdef $dstsds ; store double float from secondary using ds:bx ifndef LONGPTR intrdef $dsts endif mov cx,ds mov es,cx jmp short dodsts intrdef $dstsss ; store double float from secondary using ss:bx mov cx,ss mov es,cx jmp short dodsts intrdef $dstses ; store double float from secondary using es:bx ifdef LONGPTR intrdef $dsts endif dodsts: mov ax,flprm xchg ax,flsec mov flprm,ax ifdef FARPROC call far ptr $dstes else call $dstes endif mov ax,flprm xchg ax,flsec mov flprm,ax ret intrdef $dpshs ;push double float onto the stack ;from the primary accumulator pop ax ;fetch return address ifdef FARPROC pop dx endif sub sp,8 ;make room for double on stack mov bx,ss mov es,bx mov bx,sp ;address of place to store ifdef FARPROC push dx endif push ax ;put return address back jmp near ptr dodsts ; intrdef $dpsh ;push double float onto the stack ;from the primary accumulator pop ax ;fetch return address ifdef FARPROC pop dx endif sub sp,8 ;make room for double on stack mov bx,ss mov es,bx mov bx,sp ;address of place to store ifdef FARPROC push dx endif push ax ;put return address back jmp near ptr dodst ; intrdef $dpopp ;pop double float into secondary accum push bx push es mov bx,ss mov es,bx mov bx,sp add bx,FPTRSIZE+4 ;address of data to load ifdef FARPROC call far ptr $dldpes else call $dldpes endif pop es pop bx ret 8 ;return and de-allocate space ; intrdef $dpop ;pop double float into secondary accum push bx push es mov bx,ss mov es,bx mov bx,sp add bx,FPTRSIZE+4 ;address of data to load ifdef FARPROC call far ptr $dldses else call $dldses endif pop es pop bx ret 8 ;return and de-allocate space intrdef $dlip ;load double immediate primary push bp mov bp,sp ifdef FARPROC les bx,2[bp] else mov bx,cs mov es,bx mov bx,2[bp] endif add 2[bp],8 ;skip over double constant in code pop bp jmp dodldp intrdef $dlis ;load double immediate secondary push bp mov bp,sp ifdef FARPROC les bx,2[bp] else mov bx,cs mov es,bx mov bx,2[bp] endif add 2[bp],8 ;skip over double constant in code pop bp jmp dolds intrdef $dswap ;exchange primary and secondary mov ax,flsec xchg ax,flprm mov flsec,ax ret intrdef $dng ;negate primary mov bx,flprm cmp -2[bx],0 je no_flip xor byte ptr [bx],80H ;flip sign no_flip: ret intrdef $dtst ;test if primary is zero mov bx,flprm cmp word ptr -2[bx],0 jne true sub ax,ax ret true: sub ax,ax inc ax ret intrdef $dcmp ;compare primary and secondary push di push si std mov si,flprm mov di,ds mov es,di mov di,flsec mov al,byte ptr [si] test al,al ;is primary negative js dcneg ; primary is positive xor al,byte ptr [di] ;check if signs the same js p_gt_s ;differ then p > s jmp short docomp dcneg: ;primary is negative xor al,byte ptr [di] ;check if signs the same js p_lt_s ;differ the p < s xchg di,si ;both negative reverse sense of test docomp: sub di,2 ;back up to exponent sub si,2 mov cx,5 ;test exponent + 4 words of fraction repe cmps acc1, es:acc2 jb p_lt_s ja p_gt_s ;return 0 if p == s xor ax,ax jmp short cmp_return ;return 0 if p == s p_lt_s: ;return < 0 if p < s xor ax,ax dec ax jmp short cmp_return ; p_gt_s: ; > 0 if p > s xor ax,ax inc ax cmp_return: pop si pop di cld ret intrdef $dsb ;subtract secondary from primary mov bx,flsec xor byte ptr [bx],80H ;flip sign of secondary ;and fall thru into add routine intrdef $dad ;add secondary to primary pushf push bp push si push di std mov si,flprm mov di,ds mov es,di mov di,flsec mov cx,word ptr -2[si] ;get exponent of primary sub cx,word ptr -2[di] ;compute magnitude difference jae order_ok xchg si,di ;make largest number primary mov flprm,si mov flsec,di neg cx ;fix exponent difference order_ok: cmp cx,64 ;see if numbers overlap jna add_ok ;no overlap just return largest number pop di pop si pop bp popf ret add_ok: lea si,-3[di] mov di,offset temp+7 sub al,al cx_check: cmp cx,8 ;more than a byte to shift ? jb shift_it ;no, then shift remaining part over stos byte ptr [di] sub cx,8 jmp cx_check shift_it: sub dl,dl shift_loop: mov ah,dl lods byte ptr [si] mov dl,al shr ax,cl stos byte ptr [di] cmp di,offset temp-2 jae shift_loop ; mov si,flprm mov di,flsec mov cx,5 ;load up for loops below mov al,byte ptr [di] xor al,byte ptr [si] jns signs_same test byte ptr [di],80H ;check which is negative jnz sub_s_from_p ; ; subtract primary from secondary ; clc mov bx,0 sub_loop_1: mov ax,temp-2[bx] sbb ax,word ptr -12[bx][si] mov word ptr -12[bx][si],ax inc bx inc bx loop sub_loop_1 jmp short check_sign ; ; subtract secondary from primary ; sub_s_from_p: clc mov bx,0 sub_loop_2: mov ax,temp-2[bx] sbb word ptr -12[bx][si],ax inc bx inc bx loop sub_loop_2 check_sign: mov byte ptr [si],0 ;mark result as positive jnb do_normalize mov byte ptr [si],0FFH ;mark result as negative clc mov bx,0 mov cx,5 neg_loop: mov ax,0 sbb ax,word ptr -12[bx][si] mov word ptr -12[bx][si],ax inc bx inc bx loop neg_loop jmp short do_normalize ; ; signs of numbers are the same just add them together ; signs_same: clc mov bx,0 add_loop: mov ax,temp-2[bx] adc word ptr -12[bx][si],ax inc bx inc bx loop add_loop ;;; jmp short do_normalize ;fall through ; ; normalize number such that first byte of number is >= 0x10 ; and < 0x20 ; do_normalize: mov si,flprm lea bp,-12[si] norm: lea bx,-3[si] mov dx,word ptr -2[si] ;get exponent byte_loop: cmp byte ptr [bx],0 jne bskip_done dec bx sub dx,8 cmp bx,bp jae byte_loop ; ; number is zero ; zero_result: mov di,ds mov es,di mov di,flprm sub ax,ax mov cx,7 rep stos word ptr [di] pop di pop si pop bp popf ret bskip_done: sub cx,cx lea di,-3[si] mov ah,byte ptr [bx] dec bx cmp ah,20H jnb too_big ; mov al,byte ptr [bx] mov ch,al left_count: cmp ah,10H jae move_left shl ax,1 inc cl dec dx jmp left_count move_left: mov [di],ah dec di dec bx cmp bx,bp jb clear_tail mov ah,ch mov al,byte ptr [bx] mov ch,al shl ax,cl jmp move_left ; ; too_big: mov al,ah sub ah,ah mov ch,al right_count: inc cl inc dx shr ax,1 cmp al,20H jnb right_count move_right: stos byte ptr [di] cmp bx,bp jb clear_tail mov ah,ch mov al,byte ptr [bx] dec bx mov ch,al shr ax,cl jmp move_right ; clear_tail: mov cx,di sub cx,bp inc cx jcxz norm_done sub al,al rep stos byte ptr [di] ; norm_done: ; ; overflow/underflow checking needs to be done here ; cmp dx,0 jg no_under mov flterr_,UNDER_FLOW mov word ptr -2[si],1 jmp short clr_fraction no_under: cmp dx,2048 jl no_over mov flterr_,OVER_FLOW mov word ptr -2[si],2047 clr_fraction: mov word ptr -4[si],1000H lea di,-6[si] sub ax,ax stos word ptr [di] stos word ptr [di] stos word ptr [di] jmp fault_handler no_over: mov word ptr -2[si],dx ;save new value of exponent pop di pop si pop bp popf ret ; intrdef $ddv ;double floating divide (primary = primary/secondary) pushf push bp push si push di std mov di,ds mov es,di mov bp,flprm mov bx,flsec mov ax,ds:-2[bp] test ax,ax jnz not_zero jmp zero_result not_zero: mov dx,-2[bx] test dx,dx jnz div_ok mov flterr_,DIV_BY_ZERO jmp fault_handler div_ok: sub ax,dx add ax,1019 ;exp = Ep - Es mov ds:-2[bp],ax mov al,byte ptr [bx] xor ds:byte ptr [bp],al ; mov ax,-6[bx] ;check if easy divide case or ax,-8[bx] or ax,-10[bx] jnz hard_div ; mov si,-4[bx] lea di,ds:-4[bp] mov cx,4 mov dx,[di] cmp dx,si jb ediv_loop shl si,1 inc ds:word ptr -2[bp] ;adjust exponent ediv_loop: mov ax,-2[di] div si stos word ptr [di] loop ediv_loop sub ax,ax ;this IS the correct way div si stos word ptr [di] jmp do_normalize ; hard_div: lea si,ds:-4[bp] lea di,-4[bx] mov cx,4 repe cmps acc1, es:acc2 jne do_div ; numbers are the same so answer is 1 add ds:word ptr -2[bp],4 ;adjust exponent lea di,ds:-4[bp] mov ax,1000H stos es:acc1 sub ax,ax stos es:acc1 stos es:acc1 stos es:acc1 mov si,bp mov dx,word ptr -2[si] jmp norm_done ; do_div: mov ds:word ptr -12[bp],0 mov ax,ds:-10[bp] mov dx,ds:-8[bp] mov si,ds:-6[bp] mov di,ds:-4[bp] jb dont_shift inc ds:word ptr -2[bp] ;fix exponent shr di,1 rcr si,1 rcr dx,1 rcr ax,1 dont_shift: sub cx,cx sub bp,4 mov loop_count,4 bdiv_loop: mov lcnt1,16 div_loop: shl cx,1 shl ax,1 rcl dx,1 rcl si,1 rcl di,1 sub ax,word ptr -10[bx] sbb dx,word ptr -8[bx] sbb si,word ptr -6[bx] sbb di,word ptr -4[bx] js zero_bit one_bit: inc cx ;set bit in quotient dec lcnt1 jnz div_loop mov ds:word ptr [bp],cx sub bp,2 sub cx,cx dec loop_count jnz bdiv_loop jmp do_normalize ; bzero_loop: mov lcnt1,16 zero_loop: shl cx,1 shl ax,1 rcl dx,1 rcl si,1 rcl di,1 add ax,word ptr -10[bx] adc dx,word ptr -8[bx] adc si,word ptr -6[bx] adc di,word ptr -4[bx] jns one_bit zero_bit: dec lcnt1 jnz zero_loop mov ds:word ptr [bp],cx sub bp,2 sub cx,cx dec loop_count jnz bzero_loop jmp do_normalize ; ; intrdef $dml ;double floating multiply (primary = primary * secondary) pushf push bp push si push di std mov si,flprm mov bx,flsec mov ax,-2[si] test ax,ax jnz prm_not_zero jmp zero_result prm_not_zero: mov dx,-2[bx] test dx,dx jnz alt_not_zero jmp zero_result alt_not_zero: add ax,dx sub ax,1019 mov -2[si],ax mov al,byte ptr [bx] xor byte ptr [si],al sub ax,ax mov cx,8 mov di,ds mov es,di mov di,offset temp+6 rep stos word ptr [di] ;clear result ; mov cx,-10[bx] jcxz skip1 mov ax,-6[si] test ax,ax jz skip13 mul cx mov temp-2,dx skip13: mov ax,-4[si] test ax,ax jz skip1 mul cx add temp-2,ax adc temp,dx adc temp+2,0 skip1: mov cx,-8[bx] jcxz skip2 mov ax,-8[si] test ax,ax jz skip22 mul cx add temp-2,dx adc temp,0 adc temp+2,0 skip22: mov ax,-6[si] test ax,ax jz skip23 mul cx add temp-2,ax adc temp,dx adc temp+2,0 skip23: mov ax,-4[si] test ax,ax jz skip2 mul cx add temp,ax adc temp+2,dx adc temp+4,0 skip2: mov cx,-6[bx] jcxz skip3 mov ax,-10[si] test ax,ax jz skip3x mul cx add temp-2,dx adc temp,0 adc temp+2,0 adc temp+4,0 skip3x: mov ax,-8[si] test ax,ax jz skip31 mul cx add temp-2,ax adc temp,dx adc temp+2,0 adc temp+4,0 skip31: mov ax,-6[si] test ax,ax jz skip32 mul cx add temp,ax adc temp+2,dx adc temp+4,0 skip32: mov ax,-4[si] test ax,ax jz skip3 mul cx add temp+2,ax adc temp+4,dx adc temp+6,0 skip3: mov cx,-4[bx] jcxz skip4 mov ax,-10[si] test ax,ax jz skip41 mul cx add temp-2,ax adc temp,dx adc temp+2,0 adc temp+4,0 adc temp+6,0 skip41: mov ax,-8[si] test ax,ax jz skip42 mul cx add temp,ax adc temp+2,dx adc temp+4,0 adc temp+6,0 skip42: mov ax,-6[si] test ax,ax jz skip43 mul cx add temp+2,ax adc temp+4,dx adc temp+6,0 skip43: mov ax,-4[si] test ax,ax jz skip4 mul cx add temp+4,ax adc temp+6,dx skip4: lea di,-4[si] mov si,offset temp+6 mov cx,5 rep movs word ptr [di], word ptr [si] jmp do_normalize ; intrdef $utod pushf push bp push si push di std mov di,ds mov es,di mov di,flprm mov byte ptr [di],0 ;make sign positive mov word ptr -2[di],1023+12 ;set exponent sub di,4 stos word ptr [di] sub ax,ax stos word ptr [di] stos word ptr [di] stos word ptr [di] stos word ptr [di] jmp do_normalize ; intrdef $itod pushf push bp push si push di std mov di,ds mov es,di mov di,flprm mov byte ptr [di],0 ;make sign positive mov word ptr -2[di],1023+12 ;set exponent test ax,ax jns pos_int neg ax mov byte ptr [di],80H ;make sign negative pos_int: sub di,4 stos word ptr [di] sub ax,ax stos word ptr [di] stos word ptr [di] stos word ptr [di] stos word ptr [di] jmp do_normalize ; dornd proc near ; round the number in the primary accumulator mov di,flprm mov ax,word ptr -12[di] mov word ptr -12[di],0 cmp byte ptr -10[di],80H mov byte ptr -10[di],0 jb rndexit jne round_up test ax,ax jnz round_up or byte ptr -9[di],1 ;round up on even, down on odd ret round_up: add byte ptr -9[di],1 adc word ptr -8[di],0 adc word ptr -6[di],0 adc word ptr -4[di],0 cmp byte ptr -3[di],20h jb rndexit inc word ptr -2[di] ;bump exponent shr word ptr -4[di],1 ;and re-normalize number rcr word ptr -6[di],1 rcr word ptr -8[di],1 rcr word ptr -10[di],1 rndexit: ret dornd endp ; intrdef $xtod mov cx,1 jmp short xxtod intrdef $ul2d mov cx,0 xxtod: pushf push bp push si push di std mov di,ds mov es,di mov di,flprm mov byte ptr [di],0 ;make sign positive mov word ptr -2[di],1023+28 ;set exponent test cx,cx jz pos_long test dx,dx jns pos_long neg dx neg ax sbb dx,0 mov byte ptr [di],80H ;make sign negative pos_long: sub di,4 xchg ax,dx stos word ptr [di] xchg ax,dx stos word ptr [di] sub ax,ax stos word ptr [di] stos word ptr [di] stos word ptr [di] jmp do_normalize ; intrdef $dtou intrdef $dtoi intrdef $dtox push si push di mov si,flprm sub ax,ax mov temp,ax mov temp+2,ax mov temp+4,ax mov temp+6,ax mov ax,word ptr -2[si] sub ax,1023 js d2x_zero cmp ax,54 jae d2x_zero mov di,ds mov es,di mov di,offset temp sub bx,bx mov cx,ax mov ax,4 d2x_count: sub cx,ax jbe d2x_cdone dec bx mov ax,8 jmp d2x_count d2x_cdone: mov dl,byte ptr -3[si][bx] mov byte ptr [di],dl inc di inc bx jle d2x_cdone neg cx mov ax,temp mov dx,temp+2 mov bx,temp+4 jcxz d2x_nshift d2x_shift: shr bx,1 rcr dx,1 rcr ax,1 loop d2x_shift d2x_nshift: test byte ptr [si],80H jz d2x_ret neg dx neg ax sbb dx,0 d2x_ret: pop di pop si ret d2x_zero: sub ax,ax sub dx,dx pop di pop si ret intrdef $dstat ; save floating state in buf es:bx push si push di mov di,bx mov si, offset flterr_ ; get start of data area mov cx, offset lcnt1+1 ; get end of data area sub cx, si ; get size rep movs byte ptr [di], byte ptr [si] ; save floating state pop di pop si ret intrdef $drest ; restore floating state from buf es:bx push si push di push ds mov dx,ds ; swap segment registers mov cx,es mov ds,cx mov es,dx mov si,bx mov di, offset flterr_ ; get start of data area mov cx, offset lcnt1+1 ; get end of data area sub cx, di ; get size rep movs byte ptr [di], byte ptr [si] ; restore floating state pop ds pop di pop si ret ; ; fault_handler: pop di pop si pop bp popf ret ; ifndef INTERNAL $floats endp finish end endif fsubs87.asm ifndef INTERNAL ; Copyright (C) 1983 by Manx Software Systems ; page 54,130 ; :ts=8 ; floating point system error codes: include lmacros.h UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; internal $floats dataseg segment word public 'data' public flterr_ flterr_ dw 0 second db 8 dup (?) work dw 4 dup (?) status dw 0 extrn chop_ctl:word, round_ctl:word, rdown_ctl:word dataseg ends assume ds:dataseg ifdef FARPROC frame equ 4 else frame equ 2 endif endif ifdef INTERNAL ; ; In the table 0 -- number is valid ; 1 -- number is +/- NAN ; 2 -- number is +/- infinity ; 3 -- number is +/- unnormal ; 4 -- number is +/- denormal ; 5 -- register is marked empty oktab db 3,1,3,1,0,2,0,2,0,5,0,5,4,5,4,5 intrdef $isnan push bp mov bp,sp sub sp,2 fxam fstsw word ptr -2[bp] fwait mov bl,byte ptr -1[bp] and bl,047h test bl,40h jz noc3 or bl,08h noc3: and bx,0fh ; mask to get c3 c2 c1 and c0 bits mov al,cs:byte ptr oktab[bx] cbw test ax,ax mov sp,bp pop bp ret endif intrdef $fldpds ;load single float into primary accum ifndef LONGPTR intrdef $fldp endif finit fld ds:dword ptr[bx] ret intrdef $fldpss ;load single float into primary accum finit fld ss:dword ptr[bx] ret intrdef $fldpes ifdef LONGPTR intrdef $fldp ;load single float into primary accum endif finit fld es:dword ptr[bx] ret intrdef $fldsds ;load single float into secondary accum ifndef LONGPTR intrdef $flds endif fld ds:dword ptr[bx] fstp qword ptr second ret intrdef $fldsss ;load single float into secondary accum fld ss:dword ptr[bx] fstp qword ptr second ret intrdef $fldses ifdef LONGPTR intrdef $flds ;load single float into secondary accum endif fld es:dword ptr[bx] fstp qword ptr second ret intrdef $fstds ;store single at addr in BX ifndef LONGPTR intrdef $fst endif fst ds:dword ptr[bx] fwait ret intrdef $fstss ;store single at addr in BX fst ss:dword ptr[bx] fwait ret intrdef $fstes ifdef LONGPTR intrdef $fst ;store single at addr in BX endif fst es:dword ptr[bx] fwait ret intrdef $fstsds ;store single at addr in BX ifndef LONGPTR intrdef $fsts endif fld qword ptr second fstp ds:dword ptr[bx] fwait ret intrdef $fstsss ;store single at addr in BX fld qword ptr second fstp ss:dword ptr[bx] fwait ret intrdef $fstses ifdef LONGPTR intrdef $fsts ;store single at addr in BX endif fld qword ptr second fstp es:dword ptr[bx] fwait ret intrdef $dldpds ;load double float into primary accum ifndef LONGPTR intrdef $dldp endif finit fld ds:qword ptr[bx] ret intrdef $dldpss ;load double float into primary accum finit fld ss:qword ptr[bx] ret intrdef $dldpcs ;load double float into primary accum finit ifndef FARPROC fld cs:qword ptr[bx] else mov cx,bx mov bx,sp mov bx,ss:2[bx] xchg cx,bx mov es,cx fld es:qword ptr[bx] endif ret intrdef $dldpes ifdef LONGPTR intrdef $dldp ;load double float into primary accum endif finit fld es:qword ptr[bx] ret intrdef $dldsds ifndef LONGPTR intrdef $dlds endif push di push si push ds mov cx,ds mov es,cx jmp dodldsx intrdef $dldsss mov cx,ss mov es,cx jmp dodlds intrdef $dldscs ifndef FARPROC mov cx,cs mov es,cx else mov cx,bx mov bx,sp mov bx,ss:2[bx] ; gat code segment of calling routine xchg cx,bx mov es,cx endif jmp dodlds intrdef $dldses ifdef LONGPTR intrdef $dlds ;load double float into secondary accum endif dodlds: push di push si push ds mov di,ds mov si,es mov ds,si mov es,di dodldsx: mov di,offset second mov si,bx mov cx,4 rep movsw pop ds pop si pop di ret intrdef $dstds ;store double at addr in BX ifndef LONGPTR intrdef $dst endif fst ds:qword ptr[bx] fwait ret intrdef $dstss ;store double at addr in BX fst ss:qword ptr[bx] fwait ret intrdef $dstes ifdef LONGPTR intrdef $dst ;store double at addr in BX endif fst es:qword ptr[bx] fwait ret intrdef $dstsds ;store double at addr in BX ifndef LONGPTR intrdef $dsts endif fld qword ptr second fstp ds:qword ptr[bx] fwait ret intrdef $dstsss ;store double at addr in BX fld qword ptr second fstp ss:qword ptr[bx] fwait ret intrdef $dstses ifdef LONGPTR intrdef $dsts endif fld qword ptr second fstp es:qword ptr[bx] fwait ret intrdef $dlip ;load double immediate primary pop bx ifdef FARPROC pop es finit fld es:qword ptr [bx] add bx,8 push es push bx ret else finit fld cs:qword ptr[bx] add bx,8 jmp bx endif ; intrdef $dlis ;load double immediate secondary pop bx ifdef FARPROC pop dx endif push di push si mov di,ds mov es,di mov di,offset second mov si,bx ;get return addr mov cx,4 ifdef FARPROC push ds mov ds,dx lis_lp: ;8086 doesn't handle double prefixes movs word ptr [di], word ptr [si] else lis_lp: ;8086 doesn't handle double prefixes movs word ptr [di], cs:word ptr [si] endif loop lis_lp mov bx,si ifdef FARPROC pop ds endif pop si pop di ifdef FARPROC push dx push bx ret else jmp bx endif intrdef $dpsh ;push double float onto the stack ;from the primary accumulator pop ax ;fetch return address ifdef FARPROC pop dx endif sub sp,8 ;make room for double on stack mov bx,sp ;address of place to store ifdef FARPROC push dx endif push ax ;put return address back jmp $dstss intrdef $dpshs ;push double float onto the stack ;from the primary accumulator pop ax ;fetch return address ifdef FARPROC pop dx endif sub sp,8 ;make room for double on stack mov bx,sp ;address of place to store ifdef FARPROC push dx endif push ax ;put return address back jmp $dstsss intrdef $dpopp ;pop double float into secondary accum push bx push es mov bx,sp add bx,frame+4 ;address of data to load call $dldpss pop es pop bx ret 8 ;return and de-allocate space ; intrdef $dpop ;pop double float into secondary accum push bx push es mov bx,sp add bx,frame+4 ;address of data to load call $dldsss pop es pop bx ret 8 ;return and de-allocate space ; intrdef $dswap ;exchange primary and secondary fld qword ptr second fxch fstp qword ptr second fwait ret ; intrdef $dng ;negate primary fchs ret ; intrdef $dtst ;test if primary is zero ftst fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jne ltrue sub ax,ax ret ltrue: sub ax,ax inc ax ret ; intrdef $dcmp ;compare primary and secondary fcom qword ptr second fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jb lp_lt_s ja lp_gt_s ;return 0 if p == s xor ax,ax ret ;return 0 if p == s lp_lt_s: ;return < 0 if p < s xor ax,ax dec ax ret ; lp_gt_s: ; > 0 if p > s xor ax,ax inc ax ret ; intrdef $dsb ;subtract secondary from primary fsub qword ptr second ret ; intrdef $dad ;add secondary to primary fadd qword ptr second ret ; intrdef $ddv ;double floating divide (primary = primary/secondary) fdiv qword ptr second ret ; intrdef $dml ;double floating multiply (primary = primary * secondary) fmul qword ptr second ret ; intrdef $utod mov work,ax mov work+2,0 fild dword ptr work ret ; intrdef $itod mov work,ax finit fild word ptr work ret ; intrdef $ul2d mov work,ax mov work+2,dx mov work+4,0 mov work+6,0 finit fild qword ptr work ret ; intrdef $xtod mov work,ax mov work+2,dx finit fild dword ptr work ret ; intrdef $dtou intrdef $dtoi intrdef $dtox fldcw word ptr chop_ctl fld st(0) fistp qword ptr work fldcw word ptr round_ctl fwait mov ax,work mov dx,work+2 ret intrdef $dstat ; save floating state in buf es:bx push si push di push ds mov di,bx mov si,offset flterr_ ;get start of data mov cx,offset status+2 ;get end of data sub cx,si ;get size add bx,cx ;save end rep movs byte ptr [di], byte ptr [si] ; save data mov cx,es mov ds,cx esc 101110b,[bx] ; save floating state (acts like finit) wait esc 101100b,[bx] ; restore floating state pop ds pop di pop si ret intrdef $drest ; restore floating state from buf es:bx push si push di push ds mov si,bx mov cx,es ; swap segment registers mov dx,ds mov es,dx mov ds,cx mov di,offset flterr_ ;get start of data mov cx,offset status+2 ;get end of data sub cx,di ;get size add bx,cx ;save end rep movs byte ptr [di], byte ptr [si] ; save data esc 101100b,[bx] ; restore floating state wait pop ds pop di pop si ret ifndef INTERNAL $floats endp finish end endif fsubs87s.asm ; Copyright (C) 1983 by Manx Software Systems ; page 54,130 ; :ts=8 ; floating point system error codes: include lmacros.h internal $floats UNDER_FLOW equ 1 OVER_FLOW equ 2 DIV_BY_ZERO equ 3 ; codeseg segment para public 'code' public flprm,flsec public flterr_ dataseg segment para public 'data' public $flt_inx, chop_ctl, round_ctl, rdown_ctl $flt_inx dw 0 ; 8087/software emulation switch index flterr_ dw 0 second db 8 dup (?) work dw 4 dup (?) status dw 0 flprm dw acc1 flsec dw acc2 YU dw ? VEE dw ? dw 5 dup (?) acc1 dw 7 dup (?) acc2 dw ? ; ;work area for divide and multiply routines ; dw 4 dup (?) temp dw 4 dup (?) loop_count db 0 ;iterations left (for divide) lcnt1 db 0 ;# iter. for this word of quotient chop_ctl dw 0fbfH ;control word for Chop mode round_ctl dw 03bfH ;control word for Round nearest mode rdown_ctl dw 07bfh ;control word for Round Down mode dataseg ends assume ds:dataseg ifdef FARPROC frame equ 4 CALLSZ equ 5 else frame equ 2 CALLSZ equ 3 endif $flttb87 equ this word ; 8087 hardware indirection table dw $isnan87 dw $fldses87 dw $fldpes87 dw $fstes87 dw $fstses87 dw $dlis87 dw $dldses87 dw $dlip87 dw $dldpes87 dw $dstes87 dw $dstses87 dw $dpsh87 dw $dpshs87 dw $dpop87 dw $dpopp87 dw $dswap87 dw $dng87 dw $dtst87 dw $dcmp87 dw $dsb87 dw $dad87 dw $ddv87 dw $dml87 dw $utod87 dw $itod87 dw $xtod87 dw $ul2d87 dw $dtoi87 dw $dstat87 dw $drest87 dw $fldsss87 dw $fldsds87 dw $fldpss87 dw $fldpds87 dw $fstss87 dw $fstds87 dw $fstsss87 dw $fstsds87 dw $dldsss87 dw $dldsds87 dw $dldpss87 dw $dldpds87 dw $dstss87 dw $dstds87 dw $dstsss87 dw $dstsds87 dw $dldpcs87 dw $dldscs87 dataseg segment word public 'data' $flttb equ this word ; initial indirection table $isnantb dw $isnan86 $fldsestb dw $fldses86 $fldpestb dw $fldpes86 $fstestb dw $fstes86 $fstsestb dw $fstses86 $dlistb dw $dlis86 $dldsestb dw $dldses86 $dliptb dw $dlip86 $dldpestb dw $dldpes86 $dstestb dw $dstes86 $dstsestb dw $dstses86 $dpshtb dw $dpsh86 $dpshstb dw $dpshs86 $dpoptb dw $dpop86 $dpopptb dw $dpopp86 $dswaptb dw $dswap86 $dngtb dw $dng86 $dtsttb dw $dtst86 $dcmptb dw $dcmp86 $dsbtb dw $dsb86 $dadtb dw $dad86 $ddvtb dw $ddv86 $dmltb dw $dml86 $utodtb dw $utod86 $itodtb dw $itod86 $xtodtb dw $xtod86 $ul2dtb dw $ul2d86 $dtoitb dw $dtoi86 $dstattb dw $dstat86 $dresttb dw $drest86 $fldssstb dw $fldsss86 $fldsdstb dw $fldsds86 $fldpsstb dw $fldpss86 $fldpdstb dw $fldpds86 $fstsstb dw $fstss86 $fstdstb dw $fstds86 $fstssstb dw $fstsss86 $fstsdstb dw $fstsds86 $dldssstb dw $dldsss86 $dldsdstb dw $dldsds86 $dldpsstb dw $dldpss86 $dldpdstb dw $dldpds86 $dstsstb dw $dstss86 $dstdstb dw $dstds86 $dstssstb dw $dstsss86 $dstsdstb dw $dstsds86 $dldpcstb dw $dldpcs86 $dldscstb dw $dldscs86 dataseg ends SIZFLTTB equ 48 intrdef $fltinit ; test for 8087/80287 and install new vector table if present push si push di push es mov ds:status,0 esc 28,bx ; finit (initialize 8087) xor cx,cx esc 15,ds:status ; fstcw mov cx,50 w1loop: loop w1loop ; wait for a while and status,01f3fh ; clear unused bits cmp status,0033fh ; is 8087 there? jnz no_8087 ; no, use software emulation wait esc 47,status ; fstsw status mov cx,50 w2loop: loop w2loop ; wait for a while test ds:status,0b8bfh ; all status bits should be off jnz no_8087 ; bad status, assume not there mov si,offset $flttb87 ; 8087 is there! mov $flt_inx,2 ; set index for outside routines mov ax,ds mov es,ax mov di,cs mov ds,di mov di,offset $flttb ; get pointer to indirection table mov cx,SIZFLTTB cld rep movsw ; and overwrite it with new table mov ds,ax fldcw word ptr round_ctl ;set initial control no_8087: pop es pop di pop si clc ;return OK status ret intrdef $isnan jmp $isnantb intrdef $fldses ifdef LONGPTR intrdef $flds ;load single float into secondary accum endif jmp $fldsestb intrdef $fldsss ;load single float into secondary accum jmp $fldssstb intrdef $fldsds ;load single float into secondary accum ifndef LONGPTR intrdef $flds endif jmp $fldsdstb ; intrdef $fldpes ifdef LONGPTR intrdef $fldp ;load single float into primary accum endif jmp $fldpestb ; intrdef $fldpss ;load single float into primary accum jmp $fldpsstb ; intrdef $fldpds ;load single float into primary accum ifndef LONGPTR intrdef $fldp endif jmp $fldpdstb ; intrdef $fstes ifdef LONGPTR intrdef $fst ;store single at addr in BX endif jmp $fstestb ; intrdef $fstses ifdef LONGPTR intrdef $fsts ;store single at addr in BX endif jmp $fstsestb ; intrdef $fstss ;store single at addr in BX jmp $fstsstb ; intrdef $fstds ;store single at addr in BX ifndef LONGPTR intrdef $fst endif jmp $fstdstb intrdef $fstsss ;store single at addr in BX jmp $fstssstb ; intrdef $fstsds ;store single at addr in BX ifndef LONGPTR intrdef $fsts endif jmp $fstsdstb ; intrdef $dlis ;load double immediate secondary jmp $dlistb ; intrdef $dldsss jmp $dldssstb intrdef $dldscs jmp $dldscstb intrdef $dldsds ifndef LONGPTR intrdef $dlds endif jmp $dldsdstb intrdef $dldses ifdef LONGPTR intrdef $dlds ;load double float into secondary accum endif jmp $dldsestb ; intrdef $dlip ;load double immediate primary jmp $dliptb ; intrdef $dldpss ;load double float into primary accum jmp $dldpsstb intrdef $dldpcs ;load double float into primary accum jmp $dldpcstb intrdef $dldpds ;load double float into primary accum ifndef LONGPTR intrdef $dldp endif jmp $dldpdstb intrdef $dldpes ifdef LONGPTR intrdef $dldp ;load double float into primary accum endif jmp $dldpestb ; intrdef $dstses ifdef LONGPTR intrdef $dsts endif jmp $dstsestb intrdef $dstes ifdef LONGPTR intrdef $dst ;store double at addr in BX endif jmp $dstestb intrdef $dstss ;store double at addr in BX jmp $dstsstb intrdef $dstds ;store double at addr in BX ifndef LONGPTR intrdef $dst endif jmp $dstdstb intrdef $dstsss ;store double at addr in BX jmp $dstssstb intrdef $dstsds ;store double at addr in BX ifndef LONGPTR intrdef $dsts endif jmp $dstsdstb intrdef $dpsh ;push double float onto the stack ;from the primary accumulator jmp $dpshtb ; intrdef $dpshs ;push double float onto the stack ;from the secondary accumulator jmp $dpshstb intrdef $dpopp ;pop double float into primary accum jmp $dpopptb ; intrdef $dpop ;pop double float into secondary accum jmp $dpoptb ; intrdef $dswap ;exchange primary and secondary jmp $dswaptb ; intrdef $dng ;negate primary jmp $dngtb ; intrdef $dtst ;test if primary is zero jmp $dtsttb ; intrdef $dcmp ;compare primary and secondary jmp $dcmptb ; intrdef $dsb ;subtract secondary from primary jmp $dsbtb ; intrdef $dad ;add secondary to primary jmp $dadtb ; intrdef $ddv ;double floating divide (primary = primary/secondary) jmp $ddvtb ; intrdef $dml ;double floating multiply (primary = primary * secondary) jmp $dmltb ; intrdef $utod jmp $utodtb ; intrdef $itod jmp $itodtb ; intrdef $xtod jmp $xtodtb ; intrdef $ul2d jmp $ul2dtb ; intrdef $dtou intrdef $dtoi intrdef $dtox jmp $dtoitb intrdef $dstat jmp $dstattb intrdef $drest jmp $dresttb INTERNAL equ 1 purge intrdef intrdef macro pname pname&86 label near endm include fsubs.asm purge intrdef intrdef macro pname pname&87 label near endm include fsubs87.asm purge intrdef intrdef macro pname public pname ifdef FARPROC pname label far else pname label near endif endm $floats endp finish end ftoa.asm ; Copyright (C) 1984 by Manx Software Systems ; include lmacros.h ; ;static double rounding[] = { rounding equ this word ; 5.0e+0, db 00H,00H,00H,00H,00H,00H,014H,040H ; 0.5e+0, db 00H,00H,00H,00H,00H,00H,0e0H,03fH ; 0.5e-1, db 09aH,099H,099H,099H,099H,099H,0a9H,03fH ; 0.5e-2, db 07bH,014H,0aeH,047H,0e1H,07aH,074H,03fH ; 0.5e-3, db 0fcH,0a9H,0f1H,0d2H,04dH,062H,040H,03fH ; 0.5e-4, db 02dH,043H,01cH,0ebH,0e2H,036H,0aH,03fH ; 0.5e-5, db 0f1H,068H,0e3H,088H,0b5H,0f8H,0d4H,03eH ; 0.5e-6, db 08dH,0edH,0b5H,0a0H,0f7H,0c6H,0a0H,03eH ; 0.5e-7, db 048H,0afH,0bcH,09aH,0f2H,0d7H,06aH,03eH ; 0.5e-8, db 03aH,08cH,030H,0e2H,08eH,079H,035H,03eH ; 0.5e-9, db 095H,0d6H,026H,0e8H,0bH,02eH,01H,03eH ; 0.5e-10, db 0bbH,0bdH,0d7H,0d9H,0dfH,07cH,0cbH,03dH ; 0.5e-11, db 095H,064H,079H,0e1H,07fH,0fdH,095H,03dH ; 0.5e-12, db 011H,0eaH,02dH,081H,099H,097H,061H,03dH ; 0.5e-13, db 082H,076H,049H,068H,0c2H,025H,02cH,03dH ; 0.5e-14, db 09bH,02bH,0a1H,086H,09bH,084H,0f6H,03cH ; 0.5e-15, db 016H,056H,0e7H,09eH,0afH,03H,0c2H,03cH ; 0.5e-16, ; db 0bcH,089H,0d8H,097H,0b2H,0d2H,08cH,03cH ; 0.5e-17, ; db 097H,0d4H,046H,046H,0f5H,0eH,057H,03cH ; 0.5e-18, ; db 0acH,043H,0d2H,0d1H,05dH,072H,022H,03cH ;}; ten dw 0,0,0,4024h zero dw 0,0,0,0 ; 1, one db 00H,00H,00H,00H,00H,00H,0f0H,03fH ; 2, db 00H,00H,00H,00H,00H,00H,00H,040H ; 3, db 00H,00H,00H,00H,00H,00H,08H,040H ; 4, db 00H,00H,00H,00H,00H,00H,010H,040H ; 5, db 00H,00H,00H,00H,00H,00H,014H,040H ; 6, db 00H,00H,00H,00H,00H,00H,018H,040H ; 7, db 00H,00H,00H,00H,00H,00H,01cH,040H ; 8, db 00H,00H,00H,00H,00H,00H,020H,040H ; 9 db 00H,00H,00H,00H,00H,00H,022H,040H extrn $maxdigit:word ;this item is in CODESEG. ifdef INLINE dataseg segment word public 'data' extrn chop_ctl:word, round_ctl:word status dw 0 dataseg ends assume ds:dataseg endif IFDEF LONGPTR buffer equ es:byte ptr [di] getes macro mov es,word ptr abuf[2] endm ELSE buffer equ byte ptr [di] getes macro ; endm ENDIF ; ;ftoa(number, abuf, maxwidth, flag) ;double number; register char *abuf; procdef ftoa, <,,,> add sp,-8 push di push si mov di,word ptr abuf ;load offset word of buffer ;{ ; register int i; ; int exp, digit, decpos, ndig; ; ; ndig = maxwidth+1; mov ax,maxwidth inc ax mov word ptr -8[bp],ax ; exp = 0; mov word ptr -2[bp],0 ifdef INLINE fld qword ptr number else lea bx,number call $dldpss endif call $isnan je notnan mov cx,ax mov al,'?' cmp cx,1 beq outrange mov al,'*' cmp cx,3 je iszero cmp cx,4 je iszero jmp outrange iszero: ifdef INLINE fstp st(0) ; discard number fldz else mov bx, offset zero call $dldpcs endif notnan: ; if (number < 0.0) { ifdef INLINE ftst fstsw word ptr status fwait mov ah,byte ptr status+1 sahf je $4 jnc $3 else mov bx, offset zero call $dldscs call $dcmp je $4 ;skip scaling if zero jge $3 endif ; number = -number; ifdef INLINE fchs else call $dng endif ; *buffer++ = '-'; getes mov buffer,'-' inc di ; } $3: ; if (number > 0.0) { ; while (number < 1.0) { $5: ifdef INLINE fld1 fcomp fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jbe $6 else mov bx, offset one call $dldscs call $dcmp jge $6 endif ; number *= 10.0; ifdef INLINE fmul qword ptr ten else mov bx,offset ten call $dldscs call $dml endif ; --exp; dec word ptr -2[bp] ; } jmp $5 $6: ; while (number >= 10.0) { ifdef INLINE $7: fcom qword ptr ten fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jb $8 fdiv qword ptr ten else mov bx,offset ten call $dldscs $7: call $dcmp jl $8 ; number /= 10.0; call $ddv endif ; ++exp; inc word ptr -2[bp] ; } jmp $7 $8: ; } ; ; if (flag == 2) { /* 'g' format */ $4: mov ax,flag cmp ax,2 jne $9 ; ndig = maxwidth; mov ax,maxwidth mov word ptr -8[bp],ax ; if (exp < -4 || exp >= maxwidth) ; flag = 0; /* switch to 'e' format */ mov ax,word ptr -2[bp] cmp ax,-4 jl $11 cmp ax,maxwidth jl $10 $11: mov flag,0 $10: jmp $12 ; } else if (flag == 1) /* 'f' format */ ; ndig += exp; $9: cmp al,1 jne $13 mov ax,word ptr -2[bp] add word ptr -8[bp],ax ; ; if (ndig >= 0) { $13: $12: mov bx,word ptr -8[bp] test bx,bx jl $14 ; if ((number += round[ndig>MAXDIGIT?MAXDIGIT:ndig]) >= 10.0) { IFDEF FARPROC mov ax,es ; save es into ax mov cx,seg $maxdigit mov es,cx cmp bx,es:$maxdigit ELSE cmp bx,$maxdigit ENDIF jle $16 IFDEF FARPROC mov bx,seg $maxdigit mov es,bx mov bx,es:$maxdigit ELSE mov bx,$maxdigit ENDIF $16: IFDEF FARPROC mov es,ax ; resotre es ENDIF mov cx,3 shl bx,cl ifdef INLINE fadd qword ptr rounding[bx] fcom qword ptr ten fstsw word ptr status fwait mov ah,byte ptr status+1 sahf jb $15 fstp st(0) fld1 else add bx,offset rounding call $dldscs call $dad mov bx,offset ten call $dldscs call $dcmp jl $15 ; number = 1.0; mov bx, offset one call $dldpcs endif ; ++exp; inc word ptr -2[bp] ; if (flag) ; ++ndig; cmp flag,0 je $18 inc word ptr -8[bp] ; } $18: ; } $15: ; ; if (flag) { $14: cmp flag,0 je $19 ; if (exp < 0) { mov ax,word ptr -2[bp] test ax,ax jge $20 ; *buffer++ = '0'; getes mov buffer,'0' inc di ; *buffer++ = '.'; mov buffer,'.' inc di ; i = -exp - 1; not ax mov cx,ax ; if (ndig <= 0) ; i = maxwidth; cmp word ptr -8[bp],0 jg $21 mov cx,maxwidth $21: ; while (i--) ; *buffer++ = '0'; jcxz $23 mov al,'0' rep stosb $23: ; decpos = 0; sub ax,ax ; } else { jmp short $25 $20: ; decpos = exp+1; ; } mov ax,word ptr -2[bp] inc ax jmp short $25 ; } else { $19: ; decpos = 1; mov ax,1 ; } $25: mov word ptr -6[bp],ax ifdef INLINE fldcw word ptr chop_ctl endif ; ; if (ndig > 0) { cmp word ptr -8[bp],0 jle $28 ; for (i = 0 ; ; ++i) { mov si,0 jmp short $27 $26: inc si $27: ; if (i < MAXDIGIT) { IFDEF FARPROC mov cx,es ; save es mov ax,seg $maxdigit mov es,ax cmp si,es:$maxdigit mov es,cx ; resotre es ELSE cmp si,$maxdigit ENDIF jge $29 ; digit = (int)number; ifdef INLINE fist word ptr status fwait mov ax,status else call $dtoi push ax endif ; *buffer++ = digit+'0'; getes add al,'0' stosb ; number = (number - digit) * 10.0; ifdef INLINE fild word ptr status fsub fmul qword ptr ten else pop bx dec bx js no_subtract mov cl,3 shl bx,cl add bx,offset one call $dldscs call $dsb no_subtract: mov bx, offset ten call $dldscs call $dml endif jmp short $30 ; } else $29: ; *buffer++ = '0'; getes mov buffer,'0' inc di $30: ; if (--ndig == 0) ; break; dec word ptr -8[bp] jz $28 ; if (decpos && --decpos == 0) ; *buffer++ = '.'; mov ax,word ptr -6[bp] test ax,ax jz $26 dec ax mov word ptr -6[bp],ax jnz $26 getes mov buffer,'.' inc di ; } jmp $26 ; } $28: ifdef INLINE fldcw word ptr round_ctl fstp st(0) ; get rid of the value, we're done with it endif getes ; ; if (!flag) { cmp flag,0 jne $32 ; *buffer++ = 'e'; mov buffer,'e' inc di ; if (exp < 0) { ; exp = -exp; ; *buffer++ = '-'; mov al,'+' cmp word ptr -2[bp],0 jge $33 neg word ptr -2[bp] mov al,'-' ; } else ; *buffer++ = '+'; $33: stosb ; if (exp >= 100) { mov ax,word ptr -2[bp] cmp ax,100 jl $35 ; *buffer++ = exp/100 + '0'; mov cx,100 cwd idiv cx add al,'0' stosb ; exp %= 100; mov ax,dx ; } ; *buffer++ = exp/10 + '0'; $35: mov cx,10 cwd idiv cx add al,'0' stosb ; *buffer++ = exp%10 + '0'; mov ax,dx add al,'0' stosb ; } ; *buffer = 0; $32: mov buffer,0 ;} pop si pop di mov sp,bp pret outrange: mov cx,maxwidth jcxz $32 rep stosb jmp $32 ; ifdef FARPROC extrn $isnan:far else extrn $isnan:near endif ifndef INLINE ifdef FARPROC extrn $dad:far,$dsb:far,$dml:far,$ddv:far extrn $dldpcs:far,$dldpss:far,$dldscs:far extrn $dcmp:far,$dng:far,$dswap:far,$utod:far,$dtoi:far else extrn $dad:near,$dsb:near,$dml:near,$ddv:near extrn $dldpcs:near,$dldpss:near,$dldscs:near extrn $dcmp:near,$dng:near,$dswap:near,$utod:near,$dtoi:near endif endif pend ftoa finish end isnan.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h procdef _isnan,<> fld qword ptr x call $isnan pret pend _isnan ; ; In the table 0 -- number is valid ; 1 -- number is +/- NAN ; 2 -- number is +/- infinity ; 3 -- number is +/- unnormal ; 4 -- number is +/- denormal ; 5 -- register is marked empty oktab db 3,1,3,1,0,2,0,2,0,5,0,5,4,5,4,5 public $isnan $isnan proc push bp mov bp,sp sub sp,2 fxam fstsw word ptr -2[bp] fwait mov bl,byte ptr -1[bp] and bl,047h test bl,40h jz noc3 or bl,08h noc3: and bx,0fh ; mask to get c3 c2 c1 and c0 bits mov al,cs:byte ptr oktab[bx] cbw test ax,ax mov sp,bp pop bp ret $isnan endp finish end log.c #include "math.h" #include "errno.h" double log10(x) double x; { return log(x)*0.43429448190325182765; } #define A0 -0.64124943423745581147e+2 #define A1 +0.16383943563021534222e+2 #define A2 -0.78956112887491257267e+0 #define A(w) ((A2*w A1)*w A0) #define B0 -0.76949932108494879777e+3 #define B1 +0.31203222091924532844e+3 #define B2 -0.35667977739034646171e+2 #define B(w) (((w B2)*w B1)*w B0) #define C0 0.70710678118654752440 #define C1 0.693359375 #define C2 -2.121944400546905827679e-4 double log(x) double x; { double Rz, f, z, w, znum, zden, xn; int n; extern int errno; if (x <= 0.0) { errno = EDOM; return -HUGE_VAL; } f = frexp(x, &n); if (f > C0) { znum = (znum = f-0.5) - 0.5; /* the assignment prevents const. eval */ zden = f*0.5 + 0.5; } else { --n; znum = f - 0.5; zden = znum*0.5 + 0.5; } z = znum/zden; w = z*z; /* the lines below are split up to allow expansion of A(w) and B(w) */ Rz = z + z * (w * A(w) /B(w)); xn = n; return (xn*C2 + Rz) + xn*C1; } log87.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h EDOM equ 22 ;/****************************** log10 ***************************** ; Using the 8087/80287, calculate log, base 10, of x using ; the formula: ; log x = log 2 . log x ; 10 10 2 ;*/ neghuge db 099h,0bbh,0adh,058h,0f1h,0dch,0efh,0ffh botval db 0cdh,03bh,07fh,066h,09eh,0a0h,0e6h,03fh topval db 01ah,062h,0c0h,0cch,0b0h,0afh,0f4h,03fh assume cs:codeseg,ds:dataseg dataseg segment public byte 'data' extrn errno_:word ifdef STATRES result db 8 dup (?) endif dataseg ends ;double log10 (x) ;double x; ; procdef log10,<> sub sp,2 fld qword ptr x ftst fstsw word ptr -2[bp] mov ah,byte ptr -1[bp] sahf jz badval jnc okval badval: mov errno_,EDOM fstp st(0) fld cs:qword ptr neghuge jmp exit okval: fldlg2 fxch st(1) fld cs:qword ptr botval fcomp fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnae default fld cs:qword ptr topval fcomp fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnb default fld1 fsub fyl2xp1 jmp exit default: fyl2x exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend log10 ;/****************************** log ***************************** ; Using the 8087/80287, calculate log, base e, of x using ; the formula: ; log x = log 2 . log x ; e e 2 ;*/ ;double log (x) ;double x; procdef log,<> sub sp,2 fld qword ptr xx ftst fstsw word ptr -2[bp] mov ah,byte ptr -1[bp] sahf jz badval1 jnc okval1 badval1: mov errno_,EDOM fstp st(0) fld cs:qword ptr neghuge jmp exit1 okval1: fldln2 fxch st(1) fld cs:qword ptr botval fcomp fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnae default1 fld cs:qword ptr topval fcomp fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnb default1 fld1 fsub fyl2xp1 jmp exit1 default1: fyl2x exit1: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend log finish end pow.c #include "math.h" #include "errno.h" double pow(a,b) double a,b; { double answer; extern int errno; register long count; char sign, inverse; if (a == 0) { if (b <= 0) domain: errno = EDOM; return 0.0; } if (b == 0) return 1.0; /* anything raised to 0 is 1 */ inverse = sign = 0; if (modf(b,&answer) == 0) { if (answer < 0) inverse = 1, answer = -answer; if ((count = answer) == answer) { for (answer = 1.0 ; count ; count >>= 1, a *= a) if ((int)count & 1) answer *= a; if (inverse) answer = 1.0/answer; return answer; } if (a < 0) sign = 1, a = -a; if ((count&1) == 0) sign = 0; /* number is even so sign is positive */ } else if (a < 0) goto domain; answer = exp(log(a)*b); return sign ? -answer : answer; } random.c /* * Random number generator - * adapted from the FORTRAN version * in "Software Manual for the Elementary Functions" * by W.J. Cody, Jr and William Waite. */ double ran() { static long int iy = 100001; iy *= 125; iy -= (iy/2796203) * 2796203; return (double) iy/ 2796203.0; } double randl(x) double x; { double exp(); return exp(x*ran()); } sin.c #include "math.h" #include "errno.h" double cos(x) double x; { double sincos(); return sincos(x, fabs(x) + 1.57079632679489661923, 0); } double sin(x) double x; { double sincos(); if (x < 0.0) return sincos(x,-x,1); else return sincos(x,x,0); } #define R1 -0.16666666666666665052e+00 #define R2 +0.83333333333331650314e-02 #define R3 -0.19841269841201840457e-03 #define R4 +0.27557319210152756119e-05 #define R5 -0.25052106798274584544e-07 #define R6 +0.16058936490371589114e-09 #define R7 -0.76429178068910467734e-12 #define R8 +0.27204790957888846175e-14 #define YMAX 6.7465e09 static double sincos(x,y,sgn) double x,y; { double f, xn, g; extern int errno; if (y >= YMAX) { errno = ERANGE; return 0.0; } if (modf(y * 0.31830988618379067154, &xn) >= 0.5) ++xn; if ((int)xn & 1) sgn = !sgn; if (fabs(x) != y) xn -= 0.5; g = modf(fabs(x), &x); /* break into fraction and integer parts */ f = ((x - xn*(3217.0/1024)) + g) - xn*-8.9089102067615373566e-6; if (fabs(f) > 2.3283e-10) { g = f*f; f = (((((((R8*g R7)*g R6)*g R5)*g R4)*g R3)*g R2)*g R1)*g*f+f; } if (sgn) f = -f; return f; } sin87.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h EDOM equ 22 ERANGE equ 21 highval db 000h,066h,067h,0d0h,03dh,0ebh,0cfh,043h ; 4.6e+18 assume cs:codeseg,ds:dataseg dataseg segment public byte 'data' extrn errno_:word ifdef STATRES result db 8 dup (?) endif dataseg ends ;double cos (x) ;double x; procdef cos,<> sub sp,2 fld qword ptr x fabs ;y = fabs(x) ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jz zeroval jc badval ;if this is true y is not a number fcom cs:qword ptr highval fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jb goodval ;y must be < 4.6e+18 badval: mov errno_,ERANGE fstp st(0) ;clean up the stack fldz ;result is zero jmp exit zeroval: fstp st(0) ;clean up the stack fld1 ;result is one jmp exit goodval: fstp st(0) ;get rid of y fld qword ptr x ; reload x mov ax,1 call near ptr __sincos exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend cos ;double sin (x) ;double (x); procdef sin,<> sub sp,2 fld qword ptr xx fabs ; y = fabs(x) ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jz zeroval1 jc badval1 ; y is not a number fcom cs:qword ptr highval fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jb good1 ;y must be < 4.6e+18 badval1: mov errno_,ERANGE zeroval1: fstp st(0) ;clean up stack fldz ;result is zero jmp exit1 good1: fstp st(0) ;clean up the stack fld qword ptr xx ; reload xx xor ax,ax call near ptr __sincos exit1: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend sin __sincos proc near push bp mov bp,sp sub sp,2 mov cx,ax ; save flag ftst ; set the status flags fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor dx,dx ; positive sign flag sahf ja sk_pos ; j if both bits zero (number is positive) mov dx,1 ; negative sign flag sk_pos: mov word ptr -2[bp],-2 ; divide by 4 exponent fild word ptr -2[bp] ; put exponent on stack fldpi ; put pi on stack fscale ; pi/4 fxch ; put -2 before pi/4 fstp st(0) ; and discard scale factor fxch ; swap pi/4 and x (put x back on stack top) fprem ; find which octant x lies in y = x/(pi/4) fstsw word ptr -2[bp] fabs ; x = fabs(x) fwait mov al,byte ptr -1[bp] xor bx,bx test al,1 ; using least significant 3 bits of quotient jz ok1 ; determine which octant of unit circle x is in or bx,4 ok1: test al,2 jz ok2 or bx,1 ok2: test al,64 jz ok3 or bx,2 ok3: cmp cx,1 jnz noadjust mov dx,0 add bx,2 noadjust: test bx,1 jz skip1 ; j if bit not set (not odd number) fsub ; x = (pi/4) - x jmp test_it skip1: fxch ; get p/4 on top fstp st(0) ; and discard it test_it: ftst ; is x zero now? fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnz doit fstp st(0) ; pop x clean up stack fld1 ; answer is one jmp exit2 doit: fptan ; compute partial tangent x/y x on top y in st1 ; exit2: mov ax,bx and ax,3 cmp ax,2 jz noexch cmp ax,1 jz noexch fxch ; swap x and y noexch: fxch fld st(1) ; save a copy of x fmul st,st(0) ; compute x ^ 2 fxch fmul st,st(0) ; compute y ^ 2 fadd ; (x ^ 2) + (y ^ 2) fsqrt ; sqrt (x ^ 2 + y ^ 2) fdiv ; x / sqrt(x ^ 2 + y ^ 2) ; ; see if the sign needs to be changed ; shr bx,1 shr bx,1 and bx,1 cmp bx,dx jz alldone fchs ; x = - x alldone: fwait add sp,2 pop bp ret __sincos endp finish end sinh.c #include "math.h" #include "errno.h" extern int errno; #define P0 -0.35181283430177117881e+6 #define P1 -0.11563521196851768270e+5 #define P2 -0.16375798202630751372e+3 #define P3 -0.78966127417357099479e+0 #define Q0 -0.21108770058106271242e+7 #define Q1 +0.36162723109421836460e+5 #define Q2 -0.27773523119650701667e+3 #define PS(x) (((P3*x P2)*x P1)*x P0) #define QS(x) (((x Q2)*x Q1)*x Q0) double sinh(x) double x; { double y, w, z; int sign; y = x; sign = 0; if (x < 0.0) { y = -x; sign = 1; } if (y > 1.0) { w = y - 0.6931610107421875000; if (w > LOGHUGE) { errno = ERANGE; z = HUGE_VAL; } else { z = exp(w); if (w < 19.95) z -= 0.24999308500451499336 / z; z += 0.13830277879601902638e-4 * z; } if (sign) z = -z; } else if (y < 2.3e-10) z = x; else { z = x*x; z = x + x * (z*(PS(z) /QS(z))); } return z; } double cosh(x) double x; { double y, w, z; y = fabs(x); if (y > 1.0) { w = y - 0.6931610107421875000; if (w > LOGHUGE) { errno = ERANGE; return HUGE_VAL; } z = exp(w); if (w < 19.95) z += 0.24999308500451499336 / z; z += 0.13830277879601902638e-4 * z; } else { z = exp(y); z = z*0.5 + 0.5/z; } return z; } sqrt.c #include "math.h" #include "errno.h" double sqrt(x) double x; { double f, y; int n; extern int errno; if (x == 0.0) return x; if (x < 0.0) { errno = EDOM; return 0.0; } f = frexp(x, &n); y = 0.41731 + 0.59016 * f; y = (y + f/y); y = ldexp(y,-2) + f/y; /* fast calculation of y2 */ y = ldexp(y + f/y, -1); y = ldexp(y + f/y, -1); if (n&1) { y *= 0.70710678118654752440; ++n; } return ldexp(y,n/2); } sqrt87.asm ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 include lmacros.h dataseg segment word public 'data' extrn errno_:word ifdef STATRES result db 8 dup (?) endif dataseg ends assume ds:dataseg ERANGE equ -20 EDOM equ -21 procdef sqrt, <> ; ; double sqrt(d) ; sub sp,2 fld qword ptr doub ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnc sqrt_ok fchs mov errno_,EDOM sqrt_ok: fsqrt ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif fwait endif add sp,2 pret pend sqrt finish end sqrt87s.asm ; Copyright Manx Software Systems, Inc. 1985, 1987 include lmacros.h dataseg segment para public 'data' status dw ? extrn chop_ctl:word, round_ctl:word extrn errno_:word extrn $flt_inx:word dataseg ends assume ds:dataseg ; ;double sqrt(x) ;double x; procdef sqrt, <> lea bx,ss:word ptr doub call $dldpss mov cx,$flt_inx or cx,cx jz $sqrt86 ; ; ERANGE equ -20 EDOM equ -21 $sqrt87: fld qword ptr doub ftst fstsw status fwait mov ah,byte ptr status+1 sahf jnb sqrt_ok fchs mov errno_,EDOM sqrt_ok: fsqrt pret ; $sqrt86: ; ;{ ; double f, y; ; int n; ; extern int errno; add sp,$2 push di push si ; ; if (x == 0.0) ; return x; mov bx,offset zero call $dldscs call $dcmp jne $3 lea bx,ss:word ptr doub call $dldpss jmp return ; if (x < 0.0) { $3: lea bx,ss:word ptr doub call $dldpss mov bx,offset zero call $dldscs call $dcmp jge $4 ; errno = EDOM; mov word ptr errno_,22 ; return 0.0; mov bx,offset zero call $dldpcs jmp return ; } ; f = frexp(x, &n); $4: lea ax,word ptr -18[bp] ifdef LONGPTR push ss endif push ax lea bx,ss:word ptr doub call $dldpss call $dpsh call frexp_ ifdef LONGPTR add sp,12 else add sp,10 endif lea bx,word ptr -8[bp] call $dstss ; y = 0.41731 + 0.59016 * f; lea bx,word ptr -8[bp] call $dldpss mov bx, offset xcons1 call $dldscs call $dml mov bx,offset xcons2 call $dldscs call $dad lea bx,word ptr -16[bp] call $dstss ; y = (y + f/y); lea bx,word ptr -8[bp] call $dldpss lea bx,word ptr -16[bp] call $dldsss call $ddv lea bx,word ptr -16[bp] call $dldsss call $dad lea bx,word ptr -16[bp] call $dstss ; y = ldexp(y,-2) + f/y; /* fast calculation of y2 */ mov ax,-2 push ax lea bx,word ptr -16[bp] call $dldpss call $dpsh call ldexp_ add sp,10 call $dpsh lea bx,word ptr -8[bp] call $dldpss lea bx,word ptr -16[bp] call $dldsss call $ddv call $dpop call $dad lea bx,word ptr -16[bp] call $dstss ; y = ldexp(y + f/y, -1); mov ax,-1 push ax lea bx,word ptr -8[bp] call $dldpss lea bx,word ptr -16[bp] call $dldsss call $ddv lea bx,word ptr -16[bp] call $dldsss call $dad call $dpsh call ldexp_ add sp,10 lea bx,word ptr -16[bp] call $dstss ; y = ldexp(y + f/y, -1); mov ax,-1 push ax lea bx,word ptr -8[bp] call $dldpss lea bx,word ptr -16[bp] call $dldsss call $ddv lea bx,word ptr -16[bp] call $dldsss call $dad call $dpsh call ldexp_ add sp,10 lea bx,word ptr -16[bp] call $dstss ; ; if (n&1) { mov ax,word ptr -18[bp] test ax,1 jeq $5 ; y *= 0.70710678118654752440; lea bx,word ptr -16[bp] call $dldpss mov bx,offset xcons3 call $dldscs call $dml lea bx,word ptr -16[bp] call $dstss ; ++n; inc word ptr -18[bp] ; } ; return ldexp(y,n/2); $5: mov ax,word ptr -18[bp] mov cx,2 cwd idiv cx push ax lea bx,word ptr -16[bp] call $dldpss call $dpsh call ldexp_ add sp,10 return: pop si pop di mov sp,bp pop bp ret ;} $2 = -18 pend sqrt ; zero dw 0,0,0,0 xcons1 db 018H,09H,06dH,039H,097H,0e2H,0e2H,03fH xcons2 db 0f7H,0ccH,092H,00H,035H,0b5H,0daH,03fH xcons3 db 0cdH,03bH,07fH,066H,09eH,0a0H,0e6H,03fH ifdef FARPROC extrn frexp_:far extrn ldexp_:far extrn $dad:far,$dsb:far,$dml:far,$ddv:far extrn $dldpss:far,$dldpcs:far,$dldscs:far,$dldsss:far,$dstss:far extrn $dcmp:far,$dtst:far extrn $dpsh:far,$dpopp:far,$dpop:far,$dng:far,$dswap:far extrn $itod:far,$utod:far,$xtod:far extrn $dtoi:far,$dtou:far,$dtox:far else extrn frexp_:near extrn ldexp_:near extrn $dad:near,$dsb:near,$dml:near,$ddv:near extrn $dldpss:near,$dldpcs:near,$dldscs:near,$dldsss:near,$dstss:near extrn $dcmp:near,$dtst:near extrn $dpsh:near,$dpopp:near,$dpop:near,$dng:near,$dswap:near extrn $itod:near,$utod:near,$xtod:near extrn $dtoi:near,$dtou:near,$dtox:near endif dataseg segment para public 'data' extrn errno_:word dataseg ends finish end tan.c #include "math.h" #include "errno.h" extern int errno; static double tansub(); #if MPU8080 || MPUZ80 || MPU6502 #define TOOSMALL (1.0/HUGE_VAL) #else #define TOOSMALL TINY_VAL #endif double cotan(x) double x; { double y; y = fabs(x); if (y < TOOSMALL) { errno = ERANGE; if (x < 0.0) return -HUGE_VAL; else return HUGE_VAL; } return tansub(x,y,2); } double tan(x) double x; { return tansub(x, fabs(x), 0); } #define P1 -0.13338350006421960681e+0 #define P2 +0.34248878235890589960e-2 #define P3 -0.17861707342254426711e-4 #define Q0 +1.0 #define Q1 -0.46671683339755294240e+0 #define Q2 +0.25663832289440112864e-1 #define Q3 -0.31181531907010027307e-3 #define Q4 +0.49819433993786512270e-6 #define P(f,g) (((P3*g P2)*g P1)*g*f + f) #define Q(g) ((((Q4*g Q3)*g Q2)*g Q1)*g Q0) #define YMAX 6.74652e09 static double tansub(x, y, flag) double x,y; { double f, g, xn; double xnum, xden; if (y > YMAX) { errno = ERANGE; return 0.0; } if (fabs(modf(x*0.63661977236758134308, &xn)) >= 0.5) xn += (x < 0.0) ? -1.0 : 1.0; f = modf(x, &g); f = ((g - xn*(3217.0/2048)) + f) - xn*-4.454455103380768678308e-6; if (fabs(f) < 2.33e-10) { xnum = f; xden = 1.0; } else { g = f*f; xnum = P(f,g); xden = Q(g); } flag |= ((int)xn & 1); switch (flag) { case 1: /* A: tan, xn odd */ xnum = -xnum; case 2: /* B: cotan, xn even */ return xden/xnum; case 3: /* C: cotan, xn odd */ xnum = -xnum; case 0: /* D: tan, xn even */ return xnum/xden; } return 0.0; } tan87.asm ;:ts=8 Copyright Manx Software Systems, Inc. 1986 include lmacros.h ERANGE equ 21 EDOM equ 22 highval db 000h,066h,067h,0d0h,03dh,0ebh,0cfh,043h ; 4.6e+18 one dw 0,0,0,3ff0h ; 1.0 zero dw 0,0,0,0 ; 0.0 dataseg segment public byte 'data' extrn errno_:word ifdef STATRES result db 8 dup (?) endif dataseg ends assume cs:codeseg,ds:dataseg ;double cotan(x) ;double x; procdef cotan,<> sub sp,2 push word ptr errno_ mov ax,0 mov word ptr errno_,ax mov ax,word ptr xx+6 push ax mov ax,word ptr xx+4 push ax mov ax,word ptr xx+2 push ax mov ax,word ptr xx push ax call tan_ add sp,8 cmp errno_,0 jz okres pop cx ;get old errno off stack fldz ;answer is zero jmp exit1 okres: pop word ptr errno_ ;restore old errno ifdef STATRES mov bx,ax ifdef LONGPTR mov ds,dx fld es:qword ptr [bx] else fld qword ptr [bx] endif endif ftst fstsw word ptr -2 [bp] fwait mov ah,byte ptr -1[bp] sahf jnz oktan mov word ptr errno_,EDOM ;domain error jmp exit1 oktan: fld1 ; load a one fdivr ; cotan(x) = 1 / tan(x) exit1: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif endif fwait add sp,2 pret pend cotan ;double tan (x) ;double x; procdef tan,<> sub sp,2 fld qword ptr x ;load x fld st(0) ;get a copy of x fabs ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jz zeroval jc badval ; value is not a number fcom cs:qword ptr highval fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jb goodval badval: mov errno_,ERANGE zeroval: fstp st(0) ; get rid of fabs(x) fstp st(0) ; get rid of x fldz jmp exit goodval: fstp st(0) ; get rid of fabs(x) fldz fcomp fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] xor dx,dx ; clear sign flag sahf jb sk_pos mov dx,1 ;sign is negative sk_pos: mov word ptr -2[bp],-2 ; divide by 4 exponent fild word ptr -2[bp] fldpi fscale ; compute pi/4 fxch ; put -2 before pi/4 fstp st(0) ; and discard (clean up stack) fxch ; get x back on stack top fprem ; figure out the octant of the result fstsw word ptr -2[bp] fwait fabs ; make x absolute mov al,byte ptr -1[bp] cbw xor bx,bx test ax,1 jnz ok1 or bx,4 ok1: test ax,2 jnz ok2 or bx,1 ok2: test ax,64 jnz ok3 or bx,2 ok3: test bx,1 jnz noadjust fsub ; pi/4 - x jmp do_it noadjust: ftst fstsw word ptr -2[bp] fwait mov ah,byte ptr -1[bp] sahf jnz do_it fstp st(0) ; discard x fld1 ; result is one jmp nochk ; do_it: fptan ; take the tangent x on top y in st1 ; nochk: mov ax,bx ; does the fraction need inversion? and ax,3 cmp ax,1 jz noswap cmp ax,2 jz noswap fxch noswap: shr bx,1 ; do we need to change the sign? and bx,1 cmp bx,dx jnz nosign fchs nosign: fdivr ; finish the tangent calculation exit: ifdef STATRES fstp qword ptr result mov ax,offset result ifdef LONGPTR mov dx,ds endif endif fwait add sp,2 pret pend tan finish end tanh.c #include "math.h" #define P0 -0.16134119023996228053e+4 #define P1 -0.99225929672236083313e+2 #define P2 -0.96437492777225469787e+0 #define Q0 +0.48402357071988688686e+4 #define Q1 +0.22337720718962312926e+4 #define Q2 +0.11274474380534949335e+3 #define gP(g) (((P2*g P1)*g P0)*g) #define Q(g) (((g Q2)*g Q1)*g Q0) double tanh(x) double x; { double f,g,r; f = fabs(x); if (f > 25.3) r = 1.0; else if (f > 0.54930614433405484570) { r = 0.5 - 1.0/(exp(f+f)+1.0); r += r; } else if (f < 2.3e-10) r = f; else { g = f*f; r = f + f* (gP(g) /Q(g)); } if (x < 0.0) r = -r; return r; }