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, r, 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*3.1416015625) + g) + xn*8.9089102067615373566e-6; if (fabs(f) > 2.3283e-10) { g = f*f; r = (((((((R8*g R7)*g R6)*g R5)*g R4)*g R3)*g R2)*g R1)*g; f += f*r; } if (sgn) f = -f; return f; } tan.c #include "math.h" #include "errno.h" extern int errno; static double tansub(); double cotan(x) double x; { double y; y = fabs(x); if (y < 1.91e-152) { errno = ERANGE; if (x < 0.0) return -HUGE; else return HUGE; } 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 (modf(x*0.63661977236758134308, &xn) >= 0.5) xn += (x < 0.0) ? -1.0 : 1.0; f = (x - xn*1.57080078125) + 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; } asin.c #include "math.h" #include "errno.h" 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) 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 "libc.h" #include "math.h" #include "errno.h" static int nopper() {;} #define PI 3.14159265358979323846 #define PIov2 1.57079632679489661923 double atan2(v,u) double u,v; { double f; int (*save)(); extern int flterr; extern int errno; if (u == 0.0) { if (v == 0.0) { errno = EDOM; return 0.0; } return PIov2; } save = Sysvec[FLT_FAULT]; Sysvec[FLT_FAULT] = nopper; flterr = 0; f = v/u; Sysvec[FLT_FAULT] = save; if (flterr == 2) /* overflow */ f = PIov2; else { if (flterr == 1) /* underflow */ f = 0.0; else f = atan(fabs(f)); 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; } 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 > 349.3) { errno = ERANGE; z = HUGE; } 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 > 349.3) { errno = ERANGE; return HUGE; } 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; } 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; } pow.c #include "math.h" #include "errno.h" double pow(a,b) double a,b; { double loga; extern int errno; if (a<=0.0) { if (a<0.0 || a==0.0 && b<=0.0) { errno = EDOM; return -HUGE; } else return 0.0; } loga = log(a); loga *= b; if (loga > LOGHUGE) { errno = ERANGE; return HUGE; } if (loga < LOGTINY) { errno = ERANGE; return 0.0; } return exp(loga); } 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 = 0.25*y + f/y; /* fast calculation of y2 */ y = 0.5 * (y + f/y); y = y + 0.5 * (f/y - y); if (n&1) { y *= 0.70710678118654752440; ++n; } return ldexp(y,n/2); } 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; } f = frexp(x, &n); if (f > C0) { znum = (f-0.5)-0.5; 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; } 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()); } exp.c #include "math.h" #include "errno.h" #define P0 0.249999999999999993e+0 #define P1 0.694360001511792852e-2 #define P2 0.165203300268279130e-4 #define Q0 0.500000000000000000e+0 #define Q1 0.555538666969001188e-1 #define Q2 0.495862884905441294e-3 #define P(z) ((P2*z + P1)*z + P0) #define Q(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; } if (x < LOGTINY) { errno = ERANGE; return 0.0; } if (fabs(x) < EPS) return 1.0; z = modf(x * 1.4426950408889634074, &xn); if (z >= 0.5) ++xn; n = xn; z = modf(x, &x); /* break x up into fraction and integer part */ g = ((x - xn*0.693359375) + z) + xn*2.1219444005469058277e-4; z = g*g; r = P(z)*g; r = 0.5 + r/(Q(z)-r); return ldexp(r,n+1); } 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; } atof.asm ; Copyright (C) 1983 by Manx Software Systems ; :ts=8 extrn .dml10, .utod, .dswap, .dad extrn .dlis, .ddv, .dng dseg msign: ds 1 esign: ds 1 dpflg: ds 1 dexp: ds 2 cseg public atof_ atof_: push b xra a sta msign ;clear mantissa sign sta esign ;clear exponent sign sta dpflg ;have not seen decimal point yet lxi h,0 shld dexp ;clear exponent to zero call .utod ;clear floating point accumulator ; lxi h,4 dad sp mov c,m ;get address of string to convert inx h mov b,m skipbl: ldax b cpi ' ' jz blank cpi 9 jnz notblank blank: inx b jmp skipbl notblank: cpi '-' jnz notneg ;not minus sign sta msign ;set negative for later jmp skpsign notneg: cpi '+' ;check for plus sign jnz getnumb skpsign: inx b ;skip over sign character getnumb: ldax b cpi '0' jc notdigit cpi '9'+1 jnc notdigit push psw call .dml10 call .dswap pop psw sui '0' mov l,a mvi h,0 call .utod call .dad lda dpflg ora a jz skpsign lhld dexp dcx h shld dexp jmp skpsign notdigit: cpi '.' jnz nomore lxi h,dpflg mvi m,1 ;set dec. pt. seen jmp skpsign ; nomore: lxi h,0 ;clear exponent ori 20H ;force to lower case cpi 'e' jnz scaleit inx b ldax b cpi '-' jnz exppos sta esign ;set exponent negative jmp nxtchr exppos: cpi '+' jnz getexp nxtchr: inx b getexp: ldax b cpi '0' jc expdone cpi '9'+1 jnc expdone sui '0' dad h ; exp *= 2 mov d,h mov e,l dad h ;exp *= 4 dad h ;exp *= 8 dad d ;exp *= 10 mov e,a mvi d,0 dad d ;exp = exp*10 + char - '0' jmp nxtchr ; expdone: lda esign ;check sign of exponent ora a jz addexp mov a,h ;negate if sign was minus cma mov h,a mov a,l cma mov l,a inx h addexp: xchg lhld dexp ;get digit count dad d ;add in exponent value shld dexp ;save for scaling later ; scaleit: ;scale number to correct value lhld dexp mov a,h ora a jp movup ;negative exponent cpi 0ffH ;test if exponent too large jnz rngerr mov a,l cma inr a mov c,a ;save for loop later cpi 166 jnc rngerr cpi 150 jc sizeok call .dlis ;divide by 1e16 since smallest will overflow db 47H,23H,86H,0f2H,6fH,0c1H,0,0 call .ddv mov a,c ;get exponent value back sui 16 mov c,a sizeok: call .dswap lxi h,1 call .utod sclp1: call .dml10 ;compute number to divide by dcr c jnz sclp1 call .dswap ;get everybody back in place call .ddv ;move into range jmp dosign ; movup: ;positive exponent scale number up jnz rngerr mov a,l ;get loop count ora a jz dosign mov c,a sclp2: call .dml10 dcr c jnz sclp2 ; dosign: lda msign ;check sign of number ora a jz return call .dng ;negate accumulator return: pop b ret ; rngerr: pop b ret end ftoa.asm ; Copyright (C) 1982, 1983 by Manx Software Systems ; :ts=8 extrn .dldp, .dlds, .utod, .dlis, .dswap, .dtst extrn .dng, .dlt, .dge, .dad, .ddv, .dml10 extrn flprm dseg chrptr: ds 2 maxdig: ds 1 ndig: ds 2 exp: ds 2 count: ds 1 fflag: ds 1 cseg rounding: ; 0.5, DB 040H,080H,00H,00H,00H,00H,00H,00H ; 0.05, DB 040H,0CH,0CCH,0CCH,0CCH,0CCH,0CCH,0CDH ; 0.005, DB 040H,01H,047H,0AEH,014H,07AH,0E1H,048H ; 0.0005, DB 03FH,020H,0C4H,09BH,0A5H,0E3H,054H,00H ; 0.00005, DB 03FH,03H,046H,0DCH,05DH,063H,088H,066H ; 0.000005, DB 03EH,053H,0E2H,0D6H,023H,08DH,0A3H,0CDH ; 0.0000005, DB 03EH,08H,063H,07BH,0D0H,05AH,0F6H,0C8H ; 0.00000005, DB 03DH,0D6H,0BFH,094H,0D5H,0E5H,07AH,066H ; 0.000000005, DB 03DH,015H,079H,08EH,0E2H,030H,08CH,03DH ; 0.0000000005, DB 03DH,02H,025H,0C1H,07DH,04H,0DAH,0D3H ; 0.00000000005, DB 03CH,036H,0F9H,0BFH,0B3H,0AFH,07BH,080H ; 0.000000000005, DB 03CH,05H,07FH,05FH,0F8H,05EH,059H,026H ; 0.0000000000005, DB 03BH,08CH,0BCH,0CCH,09H,06FH,050H,09AH ; 0.00000000000005, DB 03BH,0EH,012H,0E1H,034H,024H,0BBH,043H ; 0.000000000000005, DB 03BH,01H,068H,049H,0B8H,06AH,012H,0BAH ; ; public ftoa_ ftoa_: push b lxi h,12 dad sp mov e,m inx h mov d,m xchg shld chrptr ;buffer for converted data lxi h,16 dad sp mov a,m sta fflag ;e/f/g format flag ; lxi h,4 dad sp call .dldp ;fetch number to convert lxi h,14 dad sp mov a,m ;fetch precision sta maxdig inr a mov l,a mvi h,0 shld ndig ; lhld flprm mov a,m ora a jp notneg call .dng lhld chrptr mvi m,'-' inx h shld chrptr notneg: lxi b,0 ;clear integer exponent call .dtst jz numbok call .dlis db 041H,0aH,0,0,0,0,0,0 adjust: lhld flprm inx h mov a,m cpi 1 jm toosml jz tentest cpi 2 jnz bignum inx h inx h mov a,m cpi 27H ;number < 10000, just do divides jc quick bignum: call inverse call .dlis db 40H,19H,99H,99H,99H,99H,99H,9aH bignlp: call .dml10 inx b call .dlt jnz bignlp call inverse lhld flprm inx h inx h inx h mov a,m cpi 10 jc numbok dcx b call .dml10 jmp numbok qcklp: lhld flprm inx h mov a,m cpi 1 jnz quick tentest: inx h inx h mov a,m cpi 10 jc numbok quick: call .ddv ;divide by ten till 1 <= number < 10 inx b ;count for exponent jmp qcklp sml.lp: lhld flprm inx h mov a,m cpi 1 jp numbok toosml: call .dml10 ;multiply by ten till 1 <= number < 10 dcx b ;count for exponent jmp sml.lp ; numbok: lda fflag ;check conversion format ora a jz eformat cpi 1 jz fformat lda maxdig ;if %g then precision is # sig. digits mov l,a mvi h,0 shld ndig mov a,b ;select %f if maxdig > exp > -4, else use %e ora a jm chkm4 mov a,c cmp l jnc eformat mvi a,1 ;exp < maxdig, so use %f jmp setformat ; chkm4: mov a,c cpi -4 jc eformat ;exp < -4, so use %e fformat: lhld ndig dad b shld ndig mvi a,1 jmp setformat eformat: xra a setformat: sta fflag ; now round number according to the number of digits lhld ndig dcx h mov a,h ora a jp L1 lxi h,0 jmp L5 L1: jnz toomany mov a,l cpi 14 jc L5 toomany: lxi h,14 L5: dad h ;*2 dad h ;*4 dad h ;*8 lxi d,rounding dad d call .dlds call .dad ;add in rounding counstant ; call .dlis db 041H,0aH,0,0,0,0,0,0 call .dge ;check for rounding overflow jz rndok lxi h,1 call .utod ;and repair if necessary inx b lda fflag ora a jz rndok lhld ndig inx h shld ndig rndok: mov h,b mov l,c shld exp lda fflag ora a jz unpack mov a,b ora a mov a,c ;move for unpack jp unpack ; F format and negative exponent ; put out leading zeros lhld chrptr mvi m,'0' inx h mvi m,'.' inx h lda ndig+1 ora a jm under mov a,c cma jmp L2 under: lda maxdig L2: ora a jz zdone zdiglp: mvi m,'0' inx h dcr a jnz zdiglp zdone: shld chrptr mvi a,0ffH ;mark decpt already output ; unpack: ;when we get here A has the position for the ;decimal point mov c,a ;save decimal point position lxi h,ndig+1 ;check if ndigits is <= zero mov a,m ora a jm unpdone ;if so just quit now dcx h ora m jz unpdone ;if so just quit now lhld flprm lxi d,10 dad d mvi m,0 ;zap guard bytes inx h mvi m,0 mvi b,0 unplp: mov a,b cpi 15 mvi a,'0' jnc zerodigit lhld flprm inx h ;skip sign byte mov a,m cpi 1 mvi a,'0' jnz zerodigit inx h ;skip exponent inx h ;skip overflow add m mvi m,0 ;subtract integer portion (virtual) zerodigit: lhld chrptr mov m,a inx h shld chrptr lxi h,ndig dcr m jz unpdone mov a,b cmp c jnz mul10 lhld chrptr mvi m,'.' inx h shld chrptr mul10: call .dml10 ;multiply by 10 and re-normalize inr b jmp unplp ; unpdone: lda fflag ora a jnz alldone ; lhld chrptr mvi m,'e' inx h mvi m,'+' lda exp+1 ora a lda exp jp posexp mvi m,'-' cma inr a posexp: inx h cpi 100 jc lt100 mvi m,'1' inx h sui 100 lt100: mvi b,0 tens: cpi 10 jc lt10 inr b sui 10 jmp tens lt10: adi '0' ;ascii of last digit mov e,a ;save last digit mvi a,'0' add b ;compute second digit mov m,a inx h mov m,e inx h shld chrptr ; alldone: lhld chrptr mvi m,0 pop b ret ; inverse: call .dswap lxi h,1 call .utod jmp .ddv ;implied return ; end frexp.asm ; Copyright (C) 1982, 1983, 1984 by Manx Software Systems ; :ts=8 extrn flprm extrn .dldp, .utod public frexp_, ldexp_, modf_ ; frexp_: ;return mantissa and exponent push b lxi h,4 dad sp call calcexp ;calculate power of two exponent jnz retexp lxi b,0 retexp: lxi h,12 ;address second argument dad sp mov e,m inx h mov d,m xchg mov m,c ;return base 2 exponent inx h mov m,b popret: pop b ret ; ldexp_: ;load new exponent value (actualy add to exponent) push b lxi h,4 dad sp call calcexp jz popret ;do nothing if number is zero or unnormalized lxi h,12 ;fetch number to add to exponent dad sp mov e,m inx h mov d,m xchg dad b ;add exponents mov a,h ora a ;check sign of exponent jp posexp cma ;make positive for div and modulo below mov h,a mov a,l cma mov l,a inx h mov a,l ani 7 mov c,a ;save amount to shift call rsexp ;make power of 256 mov a,l cma inr a ;fix sign back mov l,a jmp ldrs posexp: ora l ;check if zero jz popret ;no adjustment needed mov c,l ;save to compute left shift call rsexp ;make power of 256 mov a,c ani 7 jz ldrsx inr l ;bump exponent to make right shift cma adi 9 ;compensate for +1 (c = -(x-8)) ldrsx: mov c,a ;save for loop below ldrs: xchg lhld flprm inx h mov m,e ;save exponent rsloop: dcr c jm popret lhld flprm inx h inx h mvi b,7 ora a ;clear carry rslp: inx h mov a,m rar mov m,a dcr b jnz rslp jmp rsloop ; rsexp: ora a mvi b,3 rselp: mov a,h rar mov h,a mov a,l rar mov l,a dcr b jnz rselp ret ; calcexp: call .dldp ;load into floating accumulator lhld flprm inx h mov a,m ;get exponent value cpi -64 rz mvi m,0 ;make exponent zero for return mov l,a ;get low byte of exponent rlc ;sign extend value sbb a mov h,a ;save high byte of exponent dad h dad h dad h ; exp*8 to make power of two mov b,h ; bc = exponent mov c,l lhld flprm inx h inx h inx h ;hl = first byte of mantissa mov a,m ora a rz ;unnormalized number? give up lshft: mov a,m ani 80H ;test high bit of mantissa rnz ;mantissa >= 0.5 ? yes return ;otherwise, shift number to the left one place dcx b ;and adjust exponent lxi d,7 dad d ;address of end of fraction lsloop: dcx h mov a,m ral mov m,a dcr e jnz lsloop jmp lshft ; modf_: ;split into integral and fraction parts push b lxi h,12 ;pick up address to store integral part dad sp mov c,m inx h mov b,m mov l,c mov h,b mvi e,8 ;clear out integer xra a mdclr: mov m,a inx h dcr e jnz mdclr ; lxi h,4 dad sp call .dldp lhld flprm inx h mov a,m ora a jm popret jz popret adi 64 ani 7fH mov e,a dcx h mov a,m ;get sign of number ani 80H ;isolate ora e ;combine with exponent stax b ;store away inx b inx h mov a,m ;refetch exponent inx h ;skip over exponent inx h ;skip over overflow byte cpi 7 jc expok ;limit move loop to 7 bytes mvi a,7 expok: mov e,a ;save count for loop cma adi 8 ; 7 - loop count mov d,a ;save # bytes in fraction intmov: ;copy integer part into given area mov a,m stax b inx h inx b dcr e jnz intmov ; fnorm: ;note: E is zero at start of this loop dcr d jm zfrac ;fraction is zero mov a,m ;look for non-zero byte inx h dcr e ;count for exponent of fraction ora a jz fnorm ; dcx h ;back up to good byte inr e ;fix exponent mov b,h ;save position in accumulator mov c,l lhld flprm inx h mov m,e ;store exponent inx h ;skip overflow byte mvi e,7 ;count of # that must be cleared frcmov: inx h ldax b mov m,a inx b dcr e dcr d jp frcmov xra a frcclr: ;clear out rest of register inx h mov m,a dcr e jnz frcclr pop b ret zfrac: ;fraction is zero lxi h,0 call .utod pop b ret fsubs.asm ; Copyright (C) 1982, 1983, 1984 by Manx Software Systems ; :ts=8 extrn Sysvec_ extrn lnprm extrn puterr_ dseg public flprm,flsec flprm: dw acc1 flsec: dw acc2 public flterr_ flterr_: dw 0 retsave:ds 2 YU: ds 2 VEE: ds 2 expdiff:ds 1 acc1: ds 18 acc2: ds 18 ;work area for divide and multiply routines lcnt: ds 1 ;iterations left tmpa: ds 8 ;quotient tmpb: ds 8 ;remainder work area tmpc: ds 8 ;temp for divisor cseg public .flds ;load single float into secondary accum .flds: xchg lhld flsec jmp fload ; public .fldp ;load single float into primary accum .fldp: xchg lhld flprm fload: push b ldax d ;get first byte of number mov m,a ;save sign inx h ani 7fH ;isolate exponent sui 64 ;adjust from excess 64 notation mov m,a ;and save inx h mvi m,0 ;extra byte for carry mvi b,3 ;copy 3 byte fraction ldloop: inx h inx d ldax d mov m,a dcr b jnz ldloop mvi b,5 ;clear rest to zeros xra a clloop: inx h mov m,a dcr b jnz clloop pop b ret ; public .fst ;store single at addr in HL .fst: push b xchg lhld flprm mov a,m ;get sign ani 80H ;and isolate mov b,a ;save inx h mov a,m ;get exponent adi 64 ;put into excess 64 notation ani 7fH ;clear sign bit ora b ;merge exponent and sign stax d inx h ;skip overflow byte mvi b,3 ;copy 3 bytes of fraction fstlp: inx d inx h mov a,m stax d dcr b jnz fstlp pop b ret ; public .dlis ;load double immediate secondary .dlis: pop d ;get return addr lxi h,8 ;size of double dad d push h ;put back correct return addr xchg ;fall through into .dlds ; public .dlds ;load double float into secondary accum .dlds: xchg lhld flsec jmp dload ; public .dlip ;load double immediate primary .dlip: pop d ;get return addr lxi h,8 ;size of double dad d push h ;put back correct return addr xchg ;fall through into .dldp ; public .dldp ;load double float into primary accum .dldp: xchg lhld flprm dload: push b ldax d ;get first byte of number mov m,a ;save sign inx h ani 7fH ;isolate exponent sui 64 ;adjust from excess 64 notation mov m,a ;and save inx h mvi m,0 ;extra byte for carry mvi b,7 ;copy 7 byte fraction dloop: inx h inx d ldax d mov m,a dcr b jnz dloop inx h mvi m,0 ;clear guard byte pop b ret ; public .dst ;store double at addr in HL .dst: push b push h ;save address call dornd ;round fraction to 7 bytes pop d ;restore address lhld flprm mov a,m ;get sign ani 80H ;and isolate mov b,a ;save inx h mov a,m ;get exponent adi 64 ;put into excess 64 notation ani 7fH ;clear sign bit ora b ;merge exponent and sign stax d inx h ;skip overflow byte mvi b,7 ;copy 7 bytes of fraction dstlp: inx d inx h mov a,m stax d dcr b jnz dstlp pop b ret ; public .dpsh ;push double float onto the stack .dpsh: ;from the primary accumulator pop h ;get return address shld retsave ;and save for later call dornd lhld flprm lxi d,9 dad d mov d,m ;bytes 6 and 7 dcx h mov e,m dcx h push d mov d,m ;bytes 4 and 5 dcx h mov e,m dcx h push d mov d,m ;bytes 2 and 3 dcx h mov e,m dcx h push d mov d,m ;byte 1 dcx h dcx h ;skip over carry byte mov a,m ;get exponent adi 64 ;and restore to excess 64 notation ani 7fH mov e,a dcx h mov a,m ani 80H ;isolate sign bit ora e ;combine exponent and sign mov e,a push d lhld retsave pchl ; public .dpop ;pop double float into secondary accum .dpop: pop h ;get return address shld retsave ;and save lhld flsec pop d ;exponent/sign and first fraction mov m,e ;save sign inx h mov a,e ani 7fH ;isolate exponent sui 64 ;adjust for excess 64 notation mov m,a inx h mvi m,0 ;extra byte for carry inx h mov m,d inx h pop d ;bytes 2 and 3 of fraction mov m,e inx h mov m,d inx h pop d ;bytes 4 and 5 of fraction mov m,e inx h mov m,d inx h pop d ;bytes 6 and 7 of fraction mov m,e inx h mov m,d inx h mvi m,0 ;clear guard byte lhld retsave pchl ; public .dswap ;exchange primary and secondary .dswap: lhld flsec xchg lhld flprm shld flsec xchg shld flprm ret ; public .dng ;negate primary .dng: lhld flprm mov a,m xri 80H ;flip sign mov m,a ret ; public .dtst ;test if primary is zero .dtst: lhld flprm ; mov a,m ; ora a ; jnz true inx h mov a,m cpi -64 jnz true ; inx h ; inx h ; mov a,m ; ora a ; jnz true jmp false ; public .dcmp ;compare primary and secondary ; ;return 0 if p == s p.lt.s: ;return < 0 if p < s xra a dcr a pop b ret ; p.gt.s: ; > 0 if p > s xra a inr a pop b ret ; .dcmp: push b lhld flprm xchg lhld flsec ldax d ora a jm dcneg ; primary is positive xra m ;check if signs the same jm p.gt.s ;differ then p > s jmp docomp dcneg: ;primary is negative xra m ;check if signs the same jm p.lt.s ;differ the p < s xchg ;both negative reverse sense of test docomp: inx h inx d ldax d cmp m ;compare exponents jm p.lt.s ;sign test ok since -64 < exp < 64 jnz p.gt.s mvi b,9 ;test overflow byte + 8 bytes of fraction cmploop: inx h inx d ldax d cmp m jc p.lt.s jnz p.gt.s dcr b jnz cmploop ;return 0 if p == s xra a pop b ret ; public .dsb ;subtract secondary from primary .dsb: lhld flsec mov a,m xri 80H ;flip sign of secondary mov m,a ;fall thru into add routine ; public .dad ;add secondary to primary .dad: ;DE is used as primary address ;and HL is used as secondary address push b ;clear extra bytes at end of accumulators lhld flprm lxi d,11 ;leave guard byte alone dad d mvi b,7 xra a clp1: mov m,a inx h dcr b jnz clp1 lhld flsec lxi d,11 ;leave guard byte alone dad d mvi b,7 clp2: mov m,a inx h dcr b jnz clp2 lhld flprm xchg lhld flsec inx h inx d ldax d ;primary exponent sub m ;compute difference jp ordok xchg ;swap so primary is larger cma inr a ordok: dcx d dcx h shld flsec ;fix primary and secondary xchg shld flprm cpi 9 ;check for exp diff too large jnc normalize mov c,a ;save exponent difference push h push d adi 9 ;adjust for offset mov e,a mvi d,0 dad d ;adjust address for exponent difference shld YU pop d lxi h,9 dad d shld VEE pop h xchg ;get prm in DE and scnd in HL ldax d ;sign of primary xra m ;check if signs same jp doadd ldax d ora a ;test which one is negative jm UfromV ;jump if primary is negative ;subtract V from U mvi b,7 lhld YU xchg lhld VEE sublpa: ;carry is already cleared ldax d sbb m stax d dcx d dcx h dcr b jnz sublpa brlpa: ldax d sbi 0 stax d dcx d dcr c jp brlpa xchg ;get destination into HL jmp subchk ;check for negative result ; UfromV: ;subtract U from V mvi b,7 lhld VEE xchg lhld YU sublpb: ;carry is already cleared ldax d sbb m mov m,a dcx d dcx h dcr b jnz sublpb brlpb: mvi a,0 sbb m mov m,a dcx h dcr c jp brlpb subchk: ;check for negative result inx h mov a,m ;check carry byte ora a ;test sign mvi a,1 jp makpos lxi d,15 dad d ;point to end of number neglp: mvi a,0 sbb m mov m,a dcx h dcr e jp neglp mvi a,81H ;make number negative makpos: lhld flprm mov m,a ;set sign of number jmp normalize ; doadd: ;add V to U mvi b,7 lhld YU xchg lhld VEE addlp: ;carry is already cleared ldax d adc m stax d dcx d dcx h dcr b jnz addlp crylp: ldax d aci 0 stax d dcx d dcr c jp crylp jmp normalize ; public .ddv .ddv: ;double floating divide (primary = primary/secondary) push b lhld flprm xchg lhld flsec ldax d xra m ;compute sign of result stax d ;and store inx h inx d ldax d ;primary exponent sub m ;eu-ev mov c,a ;save exponent push d push h mov a,m cpi -64 jnz d.ok pop h pop h ;throw away mvi a,3 ;flag divide by zero error sta flterr_ jmp setbig ;set to biggest possible number d.ok: inx d inx h mvi b,8 cmloop: inx d inx h ldax d cmp m jnz differ dcr b jnz cmloop ;numbers are the same give 1 as the answer pop h ;throw away pop h ;get destination addr inr c ;adjust exponent mov m,c ;save exponent inx h mvi m,0 ;clear extra byte inx h mvi m,1 ;set result mvi b,8 xra a sta flterr_ jmp zclr ; differ: ;check carry to find out smaller number pop d ;restore divisor address pop h ;restore dividend address mov m,c ;store exponent jc uok inr c ;bump exponent mov m,c dcx h ;and shift dividend right (logically) uok: push d ;save for later lxi d,9 dad d ;compute end address mvi b,8 lxi d,tmpb ;copy dividend into work area remsav: mov a,m stax d dcx h inx d dcr b jnz remsav pop h ;restore divisor addr lxi d,9 dad d ;move backwards mvi b,8 lxi d,tmpc ;copy divisor into work area divsav: mov a,m stax d dcx h inx d dcr b jnz divsav mvi b,8 lxi h,tmpa ;clear quotient buffer xra a quinit: mov m,a inx h dcr b jnz quinit mvi a,64 sta lcnt ;initialize loop counter divloop: lxi h,tmpa mvi b,16 ora a ;clear carry shlp: mov a,m adc a ;shift one bit to the left mov m,a inx h dcr b jnz shlp sbb a ani 1 mov c,a mvi b,8 lxi d,tmpb lxi h,tmpc ora a ;clear carry sublp: ldax d sbb m stax d inx d inx h dcr b jnz sublp mov a,c sbi 0 jnz zerobit onebit: lxi h,tmpa inr m lxi h,lcnt dcr m jnz divloop jmp divdone ; zerobit: lxi h,lcnt dcr m jz divdone lxi h,tmpa mvi b,16 ora a ;clear carry zshlp: mov a,m adc a ;shift one bit to the left mov m,a inx h dcr b jnz zshlp sbb a mov c,a mvi b,8 lxi d,tmpb lxi h,tmpc ora a ;clear carry daddlp: ldax d adc m stax d inx d inx h dcr b jnz daddlp mov a,c aci 0 jnz zerobit jmp onebit ; divdone: lhld flprm lxi d,12 dad d mvi m,0 dcx h mvi m,0 lxi d,tmpa mvi b,8 qusav: dcx h ldax d mov m,a inx d dcr b jnz qusav jmp normalize ; public .dml .dml: ;double floating multiply (primary = primary * secondary) push b lhld flprm xchg lhld flsec ldax d xra m ;compute sign of result stax d ;and store inx h inx d ldax d ;primary exponent cpi -64 jz zresult add m ;eu+ev stax d ;save exponent mov a,m ;check for mult by zero cpi -64 jz zresult push d ;save for later lxi d,9 dad d ;compute end address mvi b,8 lxi d,tmpc ;copy muliplicand into work area msav1: mov a,m stax d dcx h inx d dcr b jnz msav1 pop h ;restore multiplier addr lxi d,9 dad d ;move backwards mvi b,8 lxi d,tmpb ;copy multiplier into work area msav2: mov a,m stax d dcx h inx d dcr b jnz msav2 mvi b,8 lxi h,tmpa ;clear buffer xra a clrmul: mov m,a inx h dcr b jnz clrmul mvi a,64 sta lcnt ;initialize loop counter muloop: lxi h,tmpa mvi b,16 ora a ;clear carry mshlp: mov a,m adc a ;shift one bit to the left mov m,a inx h dcr b jnz mshlp jnc mnext mvi b,8 lxi d,tmpa lxi h,tmpc ora a ;clear carry maddlp: ldax d adc m stax d inx d inx h dcr b jnz maddlp ; mvi b,8 madclp: ldax d aci 0 stax d jnc mnext inx d dcr b jnz madclp ; mnext: lxi h,lcnt dcr m jnz muloop lhld flprm lxi d,12 dad d lxi d,tmpb-2 mvi b,10 msav: ldax d mov m,a inx d dcx h dcr b jnz msav jmp normalize ; ; public .deq .deq: call .dcmp jz true false: lxi h,0 xra a ret ; public .dne .dne: call .dcmp jz false true: lxi h,1 xra a inr a ret ; public .dlt .dlt: call .dcmp jm true jmp false ; public .dle .dle: call .dcmp jm true jz true jmp false ; public .dge .dge: call .dcmp jm false jmp true ; public .dgt .dgt: call .dcmp jm false jz false jmp true ; public .utod .utod: push b mov a,h ora l jz zresult xchg mvi b,0 jmp posconv ; public .itod .itod: push b mov a,h ora l jz zresult xchg mvi b,0 mov a,d ora a jp posconv cma mov d,a mov a,e cma mov e,a inx d mvi b,80H posconv: lhld flprm mov m,b ;store sign inx h mov a,d ora a jnz longcvt mvi m,1 ;set up exponent inx h mvi m,0 ;clear extra byte inx h mov m,e ;move number into accumulator mvi b,7 xra a jmp cnvlp ; longcvt: mvi m,2 ;setup exponent inx h mvi m,0 ;clear extra byte inx h mov m,d ;move number into accumulator inx h mov m,e mvi b,6 xra a cnvlp: inx h mov m,a dcr b jnz cnvlp jmp goodexit ; dornd: ; round the number in the primary accumulator lhld flprm lxi d,10 ;offset of guard byte dad d mov a,m cpi 128 rc ; < 128 do nothing jnz rndit dcx h ; == 128 make number odd mov a,m ori 1 mov m,a ret ; rndit: ; > 128 add one to fraction push b lxi b,0800H ;b = 8, and c = 0 stc ; make loop add 1 rndlp: dcx h mov a,m adc c mov m,a dcr b jnz rndlp ora a ;check for fraction overflow jnz normalize ;re-normalize number if so. pop b ret ;return if none ; normalize: lhld flprm ;get address of accum inx h mov a,m ;fetch exponent mov d,h ;save address for later mov e,l inx h mov c,a xra a cmp m ;check extra byte jnz movrgt ;non-zero move number right mvi b,8 ;search up to 8 bytes nloop: inx h cmp m jnz movleft dcr c ;adjust exponent dcr b ;count times thru jnz nloop ;zero answer zresult: xra a sta flterr_ under0: lhld flprm mvi b,10 mov m,a inx h mvi m,-64 ;so exponent will be zero after store zclr: inx h mov m,a dcr b jnz zclr pop b ret ; movleft: mvi a,8 sub b mov b,a jz chkexp ;no change in counter, no move needed dcx h ;back up to zero mov a,c stax d ;save new exponent push d ;save for rounding inx d mvi a,15 sub b ;compute # of bytes to move mov c,a ;save for loop lmovlp: mov a,m stax d inx d inx h dcr c jnz lmovlp xra a lclrlp: stax d ;pad with zeros inx d dcr b jnz lclrlp pop d ;restore accum address ; chkexp: ;check for over/under flow ldax d ;get exponent ora a jm chkunder cpi 64 jc goodexit jmp overflow ; chkunder: cpi -63 jc underflow goodexit: mvi a,0 sta flterr_ pop b ret ; movrgt: ;fraction overflow inr c ;bump exponent mov a,c stax d ;save in accum mvi b,15 push d ;save for check at end lxi h,16 dad d ;end address for backwards move mov d,h mov e,l rmovlp: dcx d ldax d mov m,a dcx h dcr b jnz rmovlp mvi m,0 ;zap overflow byte back to zero pop d ;restore exponent addr jmp chkexp ; underflow: mvi a,1 sta flterr_ call userrtn ;check for user routine to handle errors xra a lhld flprm inx h ;leave sign alone mvi m,-63 ;set to smallest non-zero value inx h mov m,a inx h mvi m,1 mvi b,8 jmp zclr ;clear rest to zero ; overflow: mvi a,2 sta flterr_ setbig: call userrtn ;check for user routine to handle errors lhld flprm inx h ;leave sign alone mvi m,63 ;set exponent at max inx h mvi m,0 ;clear overflow byte mvi a,0ffH ;and set fraction to max mvi b,7 oclr: inx h mov m,a dcr b jnz oclr inx h mvi m,0 pop b ret ; userrtn: ;handle messages lhld Sysvec_ ;any routine supplied? mov a,h ora l jz myway xchg lxi h,4 dad sp mov c,m inx h mov b,m push b lhld flterr_ push h xchg call apchl pop h pop h ;clean up arguments ret apchl: pchl ; myway: call pmsg db 'Floating point ',0 lda flterr_ cpi 1 jnz notund call pmsg db 'underflow',0 jmp mycontinue notund: cpi 2 jnz notovr call pmsg db 'overflow',0 jmp mycontinue notovr: call pmsg db 'divide by zero',0 mycontinue: call pmsg db ' at location 0x',0 lxi h,5 dad sp mov a,m push h push psw call phex2 pop psw call phex pop h dcx h mov a,m push psw call phex2 pop psw call phex lxi h,10 ;newline push h call puterr_ pop h ret ; phex2: rar rar rar rar phex: ani 15 adi '0' cpi '9'+1 jc hexok adi 'A'-'0'-10 hexok: mov l,a mvi h,0 push h call puterr_ pop h ret ; pmsg: pop b ;get address of message pmloop: ldax b inx b ora a jz pmsgdone mov l,a mvi h,0 push h call puterr_ pop h jmp pmloop pmsgdone: push b ret ; public .xtod .xtod: push b lhld flprm mvi m,0 ;clear sign inx h mvi m,3 ;set up exponent lxi d,4 dad d mov e,l mov d,h mvi b,5 xra a xtodclr: inx h mov m,a dcr b jnz xtodclr ; mvi b,4 lxi h,lnprm lda lnprm+3 ora a jp lngok ; lngloop: mvi a,0 sbb m stax d inx h dcx d dcr b jnz lngloop dcx d ;back up to sign field mvi a,080H ;mark as negative stax d jmp normalize ; lngok: mov a,m stax d inx h dcx d dcr b jnz lngok jmp normalize ; public .dtox .dtox: push b lxi h,0 shld lnprm shld lnprm+2 lxi d,lnprm ; lhld flprm mov c,m ;get sign inx h mov a,m ;get exponent ora a jz goodexit ; |x| < 1.0 so return zero jm goodexit ; cpi 5 ;check for too big jnc ltoobig ; mov b,a ;save byte count inx h ;skip overflow byte add l mov l,a jnc lxx inr h lxx: mov a,m stax d inx d dcx h dcr b jnz lxx ; mov a,c ;now check sign ora a jp goodexit mvi b,4 lxi h,lnprm d2xneg: mvi a,0 sbb m mov m,a inx h dcr b jnz d2xneg jmp goodexit ; ltoobig: xchg mov a,c ora a jm bigneg mvi m,07fH inx h mvi m,0ffH inx h mvi m,0ffH inx h mvi m,0ffH jmp oflow bigneg: mvi m,080H inx h mvi m,0 inx h mvi m,0 inx h mvi m,0 jmp oflow ; ; public .dtou .dtou: push b mvi c,0 ;flag as dtou jmp ifix ; public .dtoi .dtoi: push b mvi c,1 ;flag as dtoi ifix: lhld flprm mov b,m ;get sign inx h mov a,m ;get exponent ora a jz zeroint jp nonzero zeroint: lxi h,0 ; |x| < 1.0 so return zero jmp goodexit ; nonzero: cpi 3 ;check for too big jnc toobig ; inx h ;skip overflow byte add l mov l,a jnc xx inr h xx: mov e,m dcx h mov d,m xchg mov a,c ora a jz goodexit mov a,b ora a jp goodexit mov a,h cma mov h,a mov a,l cma mov l,a inx h jmp goodexit ; toobig: mov a,c ora a jnz bigsigned lxi h,0ffffH ;return largest unsigned # jmp oflow ; bigsigned: mov a,b ora a jm negover lxi h,7fffH ;return largest positive # jmp oflow ; negover: lxi h,8000H ;return largest negative # oflow: mvi a,2 sta flterr_ pop b ret ; public fabs_ fabs_: lhld flprm mvi m,0 ;force to positive sign ret ; public .dml10 .dml10: push b lhld flprm inx h inr m ;adjust exponent lxi d,9 dad d xra a mvi b,8 ml10lp: push b mov e,m xchg mvi h,0 dad h ;num*2 mov b,h mov c,l ;save dad h ;num*4 dad h ;num*8 dad b ;num*10 xchg add e inx h mov m,a mov a,d aci 0 dcx h dcx h pop b dcr b jnz ml10lp inx h mov m,a ;save last byte of result ora a jz normalize dcx h dcx h ;back up to exponent mov a,m ;check to be sure no overflow ora a jm m10ok cpi 64 jnc overflow m10ok: pop b ret end