{ for future debugging efforts }{$e+} PROGRAM mathpack; CONST dpmax=6; {upper limit controled by carry in simm} digmax=dpmax*2; TYPE flt = RECORD exp:integer; {exp=exponent*2 (+1 if neg mant.)} dp : ARRAY [1..dpmax] OF 0..99 END; $string255= STRING 255; $string0 = STRING 0; byte= 0..255; {short integer} VAR m,n: integer; i,j,k: byte; u,v,w: flt; i$,o$: STRING 127; error$: $string255; message$: STRING 40; FUNCTION length (x: $string255):integer;external; FUNCTION index (x,y: $string255):integer;external; PROCEDURE setlength (VAR x: $string0; y:integer);external; {it is intended that parts of this program would become} {included files [or externals] for pascalZ programs} {requiring number formats more powerful than real or} {fixed. division is slow for large number of digits} PROCEDURE errortrap (errnum: integer;message$: $string255); {error recovery or unrecoverable error exit module} VAR u,v: integer; BEGIN writeln ('ERROR TRAP FUNCTION'); writeln ( message$ ); writeln ( error$ ); writeln; CASE errnum OF 0:BEGIN writeln ('PROGRAM CANNOT RECOVER!'); u:=2; v:=u-2; u:=u DIV v END; 1:writeln ('no action taken'); 2:writeln ('maximum value returned'); 3:writeln ('zero value returned'); 4:writeln ('null string returned'); 5:writeln ('blank char returned'); ELSE:BEGIN writeln ('undefined error number = ',errnum ); errortrap (0,'undefined error handling') END {else} END; {case} END; {errortrap} {returns 0 for positive and 1 for negative} FUNCTION signdig (u:flt):integer; BEGIN signdig:=(abs(u.exp))MOD 2; END; {signdig} {returns base 10 exponent of type flt} FUNCTION expvalue (u:flt):integer; VAR i:integer; BEGIN IF ODD(u.exp) THEN i:=(u.exp-1) DIV 2 ELSE i:=u.exp DIV 2; expvalue :=i END; {expvalue} {integer to flt conversion and intitalization} PROCEDURE setF (n: integer; VAR u:flt); VAR i: byte; D: ARRAY [1..5] OF 0..9; BEGIN u.exp:=0; FOR i:=1 TO dpmax DO u.dp[i]:=0; IF NOT (n=0) THEN BEGIN IF n<0 THEN u.exp:=1; n:=abs(n); D[1]:=n DIV 10000; D[2]:=n MOD 10000 DIV 1000; D[3]:=n MOD 1000 DIV 100; D[4]:=n MOD 100 DIV 10; D[5]:=n MOD 10; IF D[1]=0 THEN IF D[2]=0 THEN IF D[3]=0 THEN IF D[4]=0 THEN BEGIN u.dp[1]:=D[5]*10 END ELSE BEGIN u.dp[1]:=D[4]*10+D[5]; u.exp:=u.exp+2 END ELSE BEGIN u.dp[1]:= D[3]*10+D[4]; u.dp[2]:= D[5]*10; u.exp:=u.exp+4 END ELSE BEGIN u.dp[1]:=D[2]*10+D[3]; u.dp[2]:=D[4]*10+D[5]; u.exp:=u.exp+6 END ELSE BEGIN u.dp[1]:=D[1]*10+D[2]; u.dp[2]:=D[3]*10+D[4]; u.dp[3]:=D[5]*10; u.exp:=u.exp+8 END END {then} END; {setF} {tests digits and not exponent} FUNCTION ztest (u: flt):boolean; VAR i: byte; value: boolean; BEGIN value:= true; i:= 1; WHILE value AND (i<=dpmax) DO IF NOT (u.dp[i]=0) THEN value:=false ELSE i:=i+1; END; {ztest} {early version of Ftostr used to debug modules} PROCEDURE dispF (u: flt); VAR i,j,k: integer; BEGIN i:= u.exp MOD 2; IF ODD(u.exp) THEN write ('-') ELSE write (' '); i:=u.dp[1] DIV 10; write (i:1); write ('.'); i:=u.dp[1] MOD 10; write (i:1); FOR i:=2 TO dpmax DO BEGIN j:=u.dp[i] DIV 10; write (j:1); j:=u.dp[i] MOD 10; write (j:1) END; write ('E'); i:=expvalue(u); IF i<0 THEN BEGIN write ('-'); i:=abs(i) END; IF i=0 THEN write ('0') ELSE BEGIN IF i>999 THEN IF i>9999 THEN write (i:5) ELSE write (i:4) ELSE IF i>99 THEN write (i:3) ELSE IF i>9 THEN write (i:2) ELSE write (i:1) END; {else} writeln END; {dispF} {this test is for algerbraic greater than} FUNCTION gtest (u,v: flt):boolean; VAR i:byte; value,decided: boolean; BEGIN if ztest(u) then u.exp:=0; if ztest(v) then v.exp:=0; value:= false; IF (ODD(u.exp)=ODD(v.exp)) THEN BEGIN IF ((u.exp DIV 2)=(v.exp DIV 2)) THEN BEGIN i:=1; decided:= false; WHILE NOT decided AND (i<=dpmax) DO BEGIN IF u.dp[i]=v.dp[i] THEN i:=i+1 ELSE BEGIN decided:= true; IF u.dp[i]>v.dp[i] THEN value:=true END END {while} END {then} ELSE IF ((u.exp DIV 2)>(v.exp DIV 2)) THEN value:= true; IF ODD(u.exp) THEN value:= NOT(value) END ELSE IF ODD(v.exp) THEN value:=true; gtest:=value END; {gtest} {fixes exponent for numbers that might be zero} procedure zfix( var u:flt); begin if ztest(u) then u.exp:=0 end; {zfix} {tests sign of mant. } FUNCTION ntest (u:flt):boolean; BEGIN IF ODD(u.exp) THEN ntest:= true ELSE ntest:= false END; {ntest} {digit shift with exp. correction remains almost the} {same number except last digit is lost} PROCEDURE sr1 (VAR u:flt); VAR i: byte; BEGIN FOR i:=dpmax DOWNTO 2 DO u.dp[i]:=u.dp[i] DIV 10+((u.dp[i-1] MOD 10)*10); u.dp[1]:=u.dp[1] DIV 10; u.exp:=u.exp+2 END; {sr1} {this time first digit is lost} PROCEDURE sl1 (VAR u:flt); VAR i:byte; BEGIN FOR i:=1 TO dpmax-1 DO u.dp[i]:=u.dp[i] MOD 10 *10+(u.dp[i+1] DIV 10); u.dp[dpmax]:= u.dp[dpmax] MOD 10 *10; u.exp:=u.exp-2 END; {sl1} {sr1,sl1,sle and sre are used by shift} PROCEDURE sle (n: integer; VAR u: flt); VAR i: byte; BEGIN n:=abs(n) DIV 2; FOR i:=1 TO dpmax DO IF (i+n)>dpmax THEN u.dp[i]:=0 ELSE U.dp[i]:=u.dp[i+n]; u.exp:=u.exp-(4*n) END; {sl2n} PROCEDURE sre (n: integer; VAR u: flt); VAR i:byte; BEGIN n:=n DIV 2; FOR i:= dpmax DOWNTO 1 DO IF (i-n)<1 THEN u.dp[i]:=0 ELSE u.dp[i]:=u.dp[i-n]; u.exp:=u.exp+(4*n) END; {sre} {handels shifts of flt numbers } {positive n is to the right} PROCEDURE shift (n: integer; VAR u: flt); BEGIN IF NOT (n=0) THEN IF n>(digmax-1) THEN setF (0,u) ELSE IF n>(0-digmax) THEN IF n<0 THEN IF n=(-1) THEN sl1(u) ELSE IF ODD(n) THEN BEGIN sl1(u); n:=n+1; sle(n,u) END ELSE sle(n,u) ELSE IF n=1 THEN sr1(u) ELSE IF ODD(n) THEN BEGIN sr1(u); n:=n-1; sre(n,u) END ELSE sre(n,u) ELSE setF(0,u); END; {shift} {chops of digits to left of decimal point} FUNCTION ipart (u:flt):flt; VAR n:byte; v:flt; BEGIN IF u.exp>=digmax THEN v:=u ELSE IF u.exp<0 THEN setf(0,v) ELSE BEGIN n:=digmax-1-(u.exp DIV 2); v:=u; shift(n,v); n:=0-n; shift (n,v); END; ipart:=v END; {ipart} {prevents zeros from being the first digit} PROCEDURE slar (VAR u: flt); VAR i:byte; notdone: boolean; n: integer; BEGIN n:=0; i:=1; notdone:=true; WHILE notdone AND (i-1=digmax THEN setF (0,v) ELSE BEGIN v:=u; IF u.exp>(0-1) THEN BEGIN n:=0-1-(u.exp DIV 2); shift (n,v) END END {else} END; {fpart} {makes positive flt's negative and vice versa} PROCEDURE chsF (VAR u:flt); BEGIN IF ODD(u.exp) THEN u.exp:=u.exp-1 ELSE u.exp:=u.exp+1; END; {chsF} {returns positive version of number} FUNCTION absF (u:flt):flt; VAR v:flt; BEGIN v:=u; v.exp:=expvalue(u)*2; absF:=v END; {absF} {used by addf and subf depending on signs involved} PROCEDURE sima (u:flt; VAR v:flt); VAR index :byte; sum,carry :integer; shiftsize :integer; exchange :flt; BEGIN IF gtest (u,v) THEN BEGIN exchange:=u; u:=v; v:=exchange END; shiftsize:=(v.exp-u.exp) DIV 2; shift (shiftsize,u); carry:=0; FOR index := dpmax DOWNTO 1 DO BEGIN sum:=u.dp[index] + v.dp[index]+carry; carry:=sum DIV 100; v.dp[index]:=sum MOD 100; END; {for} IF carry>0 THEN BEGIN shift(1,v); v.dp[1]:=v.dp[1]+(carry*10) END END; {sima} {used by addf and subf according to signs} PROCEDURE sims (u:flt; VAR v:flt); VAR index :byte; shiftsize :integer; PROCEDURE borrow; VAR i :byte; notdone :boolean; BEGIN i:=index-1; notdone:=true; WHILE notdone DO BEGIN IF v.dp[i]=0 THEN BEGIN v.dp[i]:=99; i:=i-1 END ELSE BEGIN v.dp[i]:=v.dp[i]-1; notdone:=false END END END; {borrow} BEGIN shiftsize := (v.exp-u.exp) DIV 2; shift(shiftsize,u); FOR index:=dpmax DOWNTO 1 DO IF v.dp[index]>=u.dp[index] THEN v.dp[index]:=v.dp[index]-u.dp[index] ELSE BEGIN borrow; v.dp[index]:=v.dp[index]+100-u.dp[index] END; IF ztest(v) THEN v.exp:=0 ELSE slar(v); END; {sims} {used by mulf and divf stands for simple mult. } PROCEDURE simm (u:flt; VAR v:flt); VAR w :flt; result :integer; carry :integer; h,i,k :byte; BEGIN result:=0; FOR h:= dpmax DOWNTO 1 DO BEGIN carry:=0; FOR i:=1 TO h DO BEGIN k:=h+1-i; result:=u.dp[i]*v.dp[k]+result; carry:= carry+(result DIV 100); result:= result MOD 100 END; w.dp[h]:=result; result:=carry END; w.exp:=u.exp+v.exp-2; WHILE result >0 DO BEGIN carry:=result DIV 10; result:=result MOD 10; shift(1,w); w.dp[1]:=w.dp[1]+(result*10); result :=carry END; v:=w END; {simm} {returns algebraic sum} FUNCTION addF(u,v:flt):flt; VAR ucopy,vcopy :flt; BEGIN ucopy:=u; vcopy:=v; IF (ODD(ucopy.exp)=ODD(vcopy.exp)) THEN IF ODD(ucopy.exp) THEN BEGIN ucopy.exp:=ucopy.exp-1; vcopy.exp:=vcopy.exp-1; sima(ucopy,vcopy); vcopy.exp:=vcopy.exp+1 END ELSE sima(ucopy,vcopy) ELSE IF ODD(ucopy.exp) THEN BEGIN ucopy.exp:=ucopy.exp-1; IF gtest(vcopy,ucopy) THEN sims(ucopy,vcopy) ELSE BEGIN sims(vcopy,ucopy); vcopy:=ucopy; vcopy.exp:=vcopy.exp+1 END END ELSE BEGIN vcopy.exp:=vcopy.exp-1; IF gtest(vcopy,ucopy) THEN BEGIN sims(ucopy,vcopy); vcopy.exp:=vcopy.exp +1 END ELSE BEGIN sims(vcopy,ucopy); vcopy:=ucopy END END; {else} addF:=vcopy END; {addF} {returns (v minus u) } FUNCTION subF (u,v:flt):flt; VAR w:flt; BEGIN chsF(u); w:=addF(u,v); subF:=w END; {subF} {tests for equality including sign and exponents} FUNCTION etest (u,v:flt):boolean; VAR value: boolean; index:byte; BEGIN value:=true; IF NOT(u.exp=v.exp) THEN value:=false; index:=1; WHILE value AND (index<=dpmax) DO IF u.dp[index]=v.dp[index] THEN index:=index+1 ELSE value:=false; etest:=value END; {etest} {returns product} FUNCTION mulF (u,v:flt):flt; VAR x,y:flt; BEGIN x:=u; y:=v; IF (ODD(x.exp)=ODD(y.exp)) THEN BEGIN x:=absF(x); y:=absF(y); simm(x,y); END ELSE BEGIN x:=absF(x); Y:=absF(y); simm(x,y); y.exp:=y.exp+1 END; mulF:=y END; {mulF} {division by interger n<163 will be used for trig functions} PROCEDURE diviF (n:integer; VAR u:flt); VAR rem,result,index :integer; BEGIN IF n=0 THEN BEGIN errortrap(2,'division by integer zero'); u.exp:=(u.exp MOD 2)+16000; FOR index:=1 TO dpmax DO u.dp[index]:=99; END ELSE BEGIN IF n<0 THEN BEGIN chsF(u); n:=abs(n) END; rem:=0; FOR index:=1 TO dpmax DO BEGIN result:=rem*100+u.dp[index]; rem:=result MOD n; result:=result DIV n; IF result >100 THEN u.dp[index-1]:=(result DIV 100)+u.dp[index-1]; u.dp[index]:=result MOD 100 END; {for} IF ztest(u) THEN u.exp:=0 ELSE slar(u) END; {else} END; {diviF} {equal except maybe the last digit} {note 1.00000... isn't semiequal to .999999...} FUNCTION semiequal (u,v:flt):boolean; VAR test : boolean; index : byte; BEGIN IF u.exp = v.exp THEN test := true ELSE test := false; index := 1; WHILE test AND (index < dpmax) DO BEGIN IF u.dp[index] = v.dp[index] THEN index := index + 1 ELSE test := false END; semiequal := test END; {semiequal} {used by division retruns 1/u } FUNCTION recipF (u:flt):flt; VAR one :flt; two :flt; appro :flt; temp :flt; n,e,sign :integer; temreal :real; BEGIN IF ztest (u) THEN BEGIN appro.exp:=u.exp MOD 2+16000; FOR e:=1 TO dpmax DO appro.dp[e]:=99; ERRORTRAP (2,'Divison by zero') END {then} ELSE BEGIN e:=expvalue(u); IF ODD(u.exp) THEN sign:=1 ELSE sign:=0; setF(1,one); IF etest (u,one) THEN BEGIN appro:=u; appro.exp:=(0-e)*2+(sign) END ELSE BEGIN {inside} temreal:=u.dp[1]+(u.dp[2]/100); n:=ROUND(100000.0/temreal); {sets good approx} setF(n,appro); u.exp:=0; setF(2,two); appro.exp:=-2; FOR n:=1 TO ((dpmax +1)DIV 2) DO BEGIN temp:=appro; simm(u,temp); chsF(temp); temp:=addF(two,temp); simm(temp,appro); END; {while} appro.exp:=(0-1-e)*2+sign END; END; recipF:=appro END; {recipF} {returns (v divided by u) } FUNCTION divF (u,v:flt):flt; VAR w:flt; BEGIN w:=recipF(u); divF:=mulf(w,v); END; {divF} {square root function for type flt} FUNCTION sqrtF (u:flt):flt; VAR root1,delta :flt; temp :integer; rootval :real; roottest:flt; PROCEDURE betterroot; BEGIN roottest:=root1; delta :=subF(mulF(root1,root1),u); diviF(2,delta); root1:=addF(divF(root1,delta),root1); END; {betterroot} BEGIN IF ntest(u) THEN BEGIN errortrap (1,'positive root of neg number'); u.exp:=u.exp-1 END; temp:=u.exp DIV 2; IF ODD(temp) THEN temp:=u.dp[1]*100+u.dp[2] ELSE temp:=u.dp[1]*10+(u.dp[2] DIV 10); rootval:=sqrt(temp)*100; temp:=round(rootval); setF(temp,root1); root1.exp:=(u.exp DIV 4) * 2; REPEAT betterroot UNTIL semiequal(root1,roottest); sqrtF:=root1 END; {sqrtF} {converts any string to a flt number default is} {0.0e0 if there is no digits present} PROCEDURE strtoF (num$ : $string255; VAR u :flt); VAR nextchar :char; digitflag,expflag :boolean; pastpoint,negexp :boolean; digpos,strpos :byte; value :1..9; afterE :integer; {entered part of exponent} i :integer; PROCEDURE processchar; BEGIN nextchar:=num$[strpos]; CASE nextchar OF 'E','e' :IF digitflag THEN expflag:=true; '-' :IF expflag THEN negexp:=true ELSE u.exp :=(u.exp DIV 2)*2 +1; '0' :IF expflag THEN BEGIN if afterE<1630 then afterE:=afterE*10 END ELSE if pastpoint then if digitflag then digpos:=digpos+1 else u.exp:=u.exp-2 {allows entry of .00 ... 001} else if digitflag then begin digpos:=digpos+1; u.exp:=u.exp+2 end; '.' :BEGIN pastpoint := true; END; '1','2','3','4','5','6','7','8','9' :BEGIN digitflag := true; IF expflag THEN BEGIN value:=ord(nextchar)-ord('0'); if afterE<1630 then afterE:=afterE*10+value END ELSE BEGIN IF digpos < digmax THEN BEGIN value:=ord(nextchar)-ord('0'); i:=(digpos +1) DIV 2; IF ODD(digpos) THEN u.dp[i]:=value*10 ELSE u.dp[i]:=u.dp[i]+value; digpos:=digpos+1; end; {then} IF NOT(pastpoint) THEN u.exp:=u.exp+2; END END; {digits} END; {case} END; {processchar} BEGIN setF(0,u); u.exp:=-2; afterE:=0; digitflag :=false; expflag:=false; pastpoint:=false; negexp:=false; digpos:=1; FOR strpos := 1 TO length(num$) DO processchar; IF negexp then u.exp:=u.exp-(2*afterE) else u.exp:=u.exp+(2*afterE) END; {strtoF} {$iftostr.txt } {the program is just a short demo} BEGIN error$:='MATHPACK'; writeln (error$); setlength(error$,0); append(error$,'fltmath'); m:=1739; n:=-831; setF (8246,u); setF (m,w); setF (n,v); dispF (u); dispF (w); dispF (v); shift(-1,v); dispF (v); w:=addF(u,w); dispF(w); w:=subF(u,w); dispF(w); w:=mulF(u,w); dispF(w); diviF(29,v); dispF(v); v:=recipF(w); dispF(v); writeln; v:=divF(u,w); dispF(v); writeln; dispF(w); v:=sqrtF(w); dispF(v); i$:='9.75312468E-14'; strtoF(i$,u); strtoF('-3.161',v); FOR m:=1 to 60 DO BEGIN u:=mulF(v,u); dispF(u); {for comparison purposes} Ftostr(u,12,'6'); writeln; writeln; END; repeat writeln; writeln('Enter stop to stop loop'); write('Enter number to be converted : '); readln(i$); strtoF(i$,w); Ftostr(w,10,'4') until i$='stop'; END. {mathpack.pas} .