Skip to content

Instantly share code, notes, and snippets.

@pervognsen
Created June 21, 2020 03:46
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pervognsen/cb9774af79ad2138881eec8af50360ce to your computer and use it in GitHub Desktop.
Save pervognsen/cb9774af79ad2138881eec8af50360ce to your computer and use it in GitHub Desktop.
; Math48 Floating Point Package
; Version 1.1 Revision 1
; by Anders Hejlsberg
; 2532 Bytes
;HOPTABEL
JP FPADD
JP FPSUB
JP FPMUL
JP FPDIV
JP MOD
JP PWR
JP CMP
JP SQR
JP LN
JP EXP
JP LOG
JP SIN
JP COS
JP TAN
JP ATN
JP ACPI
JP INT
JP FRAC
JP EQUAL
JP MUL10
JP FIX
JP FLOAT
JP FSTRS
JP FSTRR
JP CNVN
SIGN: EQU 80H
EXPN: EQU 80H
IWIDTH: EQU 0F0H
FWIDTH: EQU 0FH
;FLOATING POINT ADDITION.
FPADD: EXX ;Er AC negativ?
BIT 7,B
EXX
JP NZ,SUB1 ;Ja => SUB1
ADD1: EXX ;Er AC' nul?
LD A,L
OR A
EXX
RET Z ;Ja => Returner
EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
EXX
LD A,L ;Er AC nul?
OR A
JR NZ,ADD2 ;Nej => ADD2
EXX ;Returner AC'
RES 7,B ;Positivt
JR ADD10
ADD2: PUSH BC ;Gem fortegn
SET 7,B ;Saet MSB
XOR A ;Saet Z'
EX AF,AF'
EXX
SET 7,B ;Saet MSB'
LD A,L ;A=EXP'-EXP
EXX
SUB L
JR Z,ADD4 ;EXP=EXP' => ADD4
JR NC,ADD3 ;EXP<EXP' => ADD3
NEG ;Goer A positiv
EX AF,AF' ;Nulstil Z'
DEC A
EX AF,AF'
EXX ;Juster AC'
ADD3: CALL SRIGHT ;Skift til hoejre
INC L ;Er EXP=EXP'?
DEC A
JR NZ,ADD3 ;Nej => ADD3
EX AF,AF' ;Var det AC'?
JR Z,ADD4 ;Nej => ADD4
EXX ;Ja => Ombyt
ADD4: POP AF ;Hent AC fortegn
AND SIGN ;Negativt?
JR NZ,ADD5 ;Ja => ADD5
CALL ADDAC ;MANT=MANT+MANT'
JR NC,ADD9 ;Ikke overflow => ADD9
CALL RIGHT ;Roter til hoejre
OR A
INC L ;Juster exponent
JR NZ,ADD9
SCF
JR ADD10
ADD5: CALL CMPAC ;Sammenlign
CCF ;Komplementer carry og
PUSH AF ;gem som fortegn
JR Z,ADDZ ;AC=AC' => ADDZ
JR C,ADD6 ;AC>AC' => ADD6
EXX ;AC<AC' => Ombyt
ADD6: CALL SUBAC ;MANT=MANT-MANT'
ADD7: BIT 7,B ;Normaliseret?
JR NZ,ADD8 ;Ja => ADD8
CALL SLEFT ;Skift til venstre
INC L ;Er exponent -128?
DEC L
JR Z,ADDZ ;Ja => AC lig nul
DEC L ;Traek 1 fra exponent
JR ADD7
ADDZ: CALL ZERO
ADD8: POP AF ;Hent fortegn
ADD9: JR C,ADD9A ;Carry => negativt
RES 7,B
ADD9A: OR A
ADD10: EXX ;Hent AC'
POP HL
POP DE
POP BC
EXX
RET
;FLOATING POINT SUBTRAKTION
FPSUB: EXX ;Er AC negativ?
BIT 7,B
EXX
JP NZ,ADD1 ;Ja => ADD1
SUB1: CALL FPNEG ;AC=-AC
CALL ADD1 ;Laeg AC' til AC
FPNEG: INC L ;Er AC nul?
DEC L
RET Z ;Ja => Returner
EX AF,AF' ;Gem carry
LD A,B ;Komplementer fortegn
XOR SIGN
LD B,A
EX AF,AF' ;Hent carry
RET
;FLOATING POINT DIVISION.
FPDIV: EXX ;Er AC' nul?
INC L
DEC L
EXX
SCF
RET Z ;Ja => Overflow
LD A,L ;Er AC nul?
OR A
RET Z ;Ja => Returner
EXX ;Subtraher exponenter
SUB L
EXX
CCF ;Juster exponent og
CALL EXPSGN ;udregn fortegn
PUSH HL ;Opret 6 bytes work-
PUSH HL ;space
PUSH HL
ADD IX,SP
EXX ;5 bytes
LD L,5
EXX
LD A,8 ;Med hver 8 bits
DIVI1: EX AF,AF' ;Gem taeller
CALL CMPAC ;Er MANT>MANT'
JR C,DIVI2 ;Nej => DIVI2
CALL SUBAC ;Traek AC' fra AC
DIVI2: CCF ;Komplementer carry
RL L ;Roter ind i resultat
EX AF,AF' ;Hent bittaeller
DEC A ;Byte faerdig?
JR NZ,DIVI3 ;Nej => DIVI3
LD (IX+5),L ;Gem byte i buffer
DEC IX ;Peg til naeste
EXX ;Er 5 bytes klaret?
DEC L
EXX
JR Z,DIVI4 ;Ja => DIVI4
LD A,8 ;8 bits
DIVI3: CALL SLEFT ;Skift AC til venstre
JR NC,DIVI1 ;Ingen carry => DIVI1
EX AF,AF' ;Gem taeller
CALL SUBAC ;MANT=MANT-MANT'
OR A ;Nulstil carry
JR DIVI2
DIVI4: CALL SLEFT ;Udregn afrundingsbit
JR C,DIVI5
CALL CMPAC
CCF
DIVI5: POP HL ;Hent resultat
POP DE
POP BC
BIT 7,B ;Normaliseret?
JR NZ,DIVI6 ;Ja => DIVI6
CALL LEFT ;Roter afrundingsbit
JR MUL5 ;ind i resultatet
DIVI6: INC L ;Laeg 1 til exponent
JR NZ,MUL5
DEC L
SCF
JR MUL5A
;FLOATING POINT MULTIPLIKATION
FPMUL: EXX ;Er AC' nul?
LD A,L
OR A
EXX
JP Z,ZERO ;Ja => Resultat 0
LD A,L ;Er AC nul?
OR A
RET Z ;Ja => Retur
EXX ;Adder exponenter
ADD A,L
EXX ;Juster exponent og
CALL EXPSGN ;udregn fortegn
PUSH BC ;Gem AC
PUSH DE
PUSH HL
ADD IX,SP ;Peg IX til AC
CALL ZERO ;Nulstil resultat
EXX ;5 bytes
LD L,5
EXX
MUL1: LD A,8 ;Bittaeller lig 8
INC IX ;Hent ny byte
LD L,(IX+0)
MUL2: EX AF,AF' ;Gem taeller
RR L ;Roter byte til hoejre
JR NC,MUL3 ;Hvis carry saa laeg
CALL ADDAC ;AC' til resultatet
MUL3: CALL RIGHT ;Roter res. til hoejre
EX AF,AF' ;Hent taeller
DEC A ;Byte faerdig?
JR NZ,MUL2 ;Nej => MUL2
EXX ;5 bytes klaret?
DEC L
EXX
JR NZ,MUL1 ;Nej => MUL1
LD L,(IX-5) ;Hent exponent
BIT 7,B ;Normaliseret?
JR NZ,MUL4 ;Ja => MUL4
EX AF,AF' ;Hent sidste carry
CALL LEFT ;Roter res. til venstre
INC L ;Traek 1 fra exponent
DEC L
JR Z,MUL4
DEC L
MUL4: POP AF ;Fjern workspace
POP AF
POP AF
MUL5: OR A ;Status = OK
MUL5A: EX AF,AF' ;Gem status
POP AF ;Hent res. fortegn
EXX
POP BC ;Hent AC' fortegn
POP HL ;Hent AC' exponent
EXX
POP IX ;Hent IX
RES 7,B ;Erstat MSB i AC med
OR B ;fortegn
LD B,A
EX AF,AF' ;Hent status
INC L
DEC L
CALL Z,ZERO
RET
;Juster exponent og udregn fortegn.
EXPSGN: JR C,EXPS1 ;Carry => EXPS1
ADD A,EXPN ;Juster exponent
JR C,EXPS2 ;Carry => EXPS2
JR EXPS3 ;Underflow
EXPS1: ADD A,EXPN ;Juster exponent
JR C,EXPS3 ;carry => Overflow
EXPS2: LD L,A ;Gem i exponent
EX (SP),IX ;Gem IX
EXX
PUSH HL ;Gem AC' exponent
PUSH BC ;Gem AC' fortegn
LD A,B ;Udregn nyt fortegn
SET 7,B
EXX
XOR B
AND SIGN
PUSH AF
SET 7,B
PUSH IX
LD IX,0 ;Nulstil IX
RET
EXPS3: POP HL ;Juster stakken
RET C ;Carry => Returner
;Nulstil AC.
ZERO: XOR A ;Nulstil carry, expo-
LD L,A ;nent og mantissa
LD B,A
LD C,A
LD D,A
LD E,A
LD H,A
RET
;Roter AC til hoejre.
SRIGHT: OR A
RIGHT: RR B
RR C
RR D
RR E
RR H
RET
;Roter AC til venstre.
SLEFT: OR A
LEFT: RL H
RL E
RL D
RL C
RL B
RET
;Laeg AC' til AC.
ADDAC: LD A,H
EXX
ADD A,H
AAC1: EXX
LD H,A
LD A,E
EXX
ADC A,E
EXX
LD E,A
LD A,D
EXX
ADC A,D
EXX
LD D,A
LD A,C
EXX
ADC A,C
EXX
LD C,A
LD A,B
EXX
ADC A,B
EXX
LD B,A
RET
;Traek AC' fra AC.
SUBAC: LD A,H
EXX
SUB H
SAC1: EXX
LD H,A
LD A,E
EXX
SBC A,E
EXX
LD E,A
LD A,D
EXX
SBC A,D
EXX
LD D,A
LD A,C
EXX
SBC A,C
EXX
LD C,A
LD A,B
EXX
SBC A,B
EXX
LD B,A
RET
;Sammenlign AC med AC'.
CMPAC: LD A,B
EXX
CP B
EXX
RET NZ
LD A,C
EXX
CP C
EXX
RET NZ
LD A,D
EXX
CP D
EXX
RET NZ
LD A,E
EXX
CP E
EXX
RET NZ
LD A,H
EXX
CP H
EXX
RET
;FLOATING POINT COMPARE.
CMP: EXX ;Er fortegn ens?
LD A,B
EXX
XOR B
JP P,CMP1 ;Ja => CMP1
LD A,B ;Fortegn fra AC til
RLA ;carry
RET
CMP1: BIT 7,B ;Negative tal?
JR Z,CMP2 ;Nej => CMP2
CALL CMP2 ;Sammenlign abs.vaerdi
RET Z ;Ens => Returner
CCF ;Complementer resultat
RET
CMP2: LD A,L ;Er exponenter ens?
EXX
CP L
EXX
RET NZ ;Nej => Returner
OR A ;Er exponenter nul?
RET Z ;Ja => Returner
JP CMPAC ;Sammenlign AC med AC'
;FLOATING POINT INTEGER.
INT: LD A,L ;Er exponent mindre
SUB EXPN+1 ;end nul?
JP C,ZERO ;Ja => Resultat nul
INC A
EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
EX AF,AF'
CALL ZERO ;Nulstil AC'
EX AF,AF'
INT1: SCF ;Saet alle bits der har
CALL RIGHT ;en exponent stoerre
DEC A ;end eller lig nul
JR NZ,INT1
EXX ;Nulstil alle bits i AC
LD A,H ;der har en exponent
EXX ;mindre end 0
AND H
EXX
LD H,A
LD A,E
EXX
AND E
EXX
LD E,A
LD A,D
EXX
AND D
EXX
LD D,A
LD A,C
EXX
AND C
EXX
LD C,A
LD A,B
EXX
AND B
EXX
LD B,A
INT2: JP ADD10 ;Hent AC'
;FLOATING POINT FRACTION.
;FRAC(X) udregnes af X-INT(X).
FRAC: EXX
PUSH BC
PUSH DE
PUSH HL
EXX
CALL EQUAL
EXX
CALL INT
EXX
CALL FPSUB
JR INT2
;MODULUS.
;X MOD Y beregnes af FRAC(X/Y)*Y.
MOD: CALL FPDIV
RET C
CALL FRAC
JP FPMUL
;KVADRATROD.
;Kvadratroden beregnes med Newton-Raphson
;iterationsmetoden. Et gaet udregnes ud fra
;det foregaaende gaet efter formelen:
;I(n+1)=(X/I(n)+I(n))/2.
;Som foerste gaet halveres X's exponent.
;Der fortsaettes indtil ABS(I(n+1)-I(n)) er
;mindre end den halve exponent af X minus 20.
SQR: LD A,L ;Er AC nul?
OR A
RET Z ;Ja => Returer
BIT 7,B ;Er AC negativ?
SCF ;Saet carry
RET NZ ;Ja => Returner
EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
EXX
CALL EQUAL ;AC'=AC
LD A,L ;Foerste iteration:
ADD A,EXPN ;halver exponenten
SRA A
ADD A,EXPN
LD L,A ;Sammenligningsvaerdi
SUB 20 ;er den halve exponent
PUSH AF ;Gem s.vaerdi
EXX
SQR1: PUSH BC ;Gem tallet
PUSH DE
PUSH HL
CALL FPDIV ;Divider med og adder
CALL FPADD ;forrige gaet
DEC L ;Halver
PUSH BC ;Gem dette gaet
PUSH DE
PUSH HL
CALL FPSUB ;Udregn forskellen mel-
LD A,L ;lem de to gaet
POP HL ;Hent det nye gaet
POP DE
POP BC
EXX
POP HL ;Hent tallet
POP DE
POP BC
EX (SP),HL ;Hent s.vaerdi ind i H
CP H
EX (SP),HL ;Fortsaet indtil forsk.
JR NC,SQR1 ;er lille nok
POP AF ;Fjern s.vaerdi
EXX
OR A ;Nulstil carry
SQR2: JP ADD10 ;Hent AC'
;TANGENS.
;TAN(X) beregnes af SIN(X)/COS(X)
TAN: EXX
PUSH BC
PUSH DE
PUSH HL
EXX
CALL EQUAL
CALL COS
EXX
CALL SIN
CALL FPDIV
JR SQR2
;COSINUS.
;COS(X) beregnes af SIN(PI/2-X)
COS: EXX
PUSH BC
PUSH DE
PUSH HL
CALL ACPI
DEC L
CALL FPSUB
EXX
JR SINC
;SINUS.
;SIN(X) beregnes paa flg. maade:
;Hvis ABS(X)>2*PI saa X=FRAC(X/(2*PI))*2*PI
;Hvis X<0 saa X=X+2*PI
;Hvis X>PI saa X=X-PI, fortegn -
;Hvis X>PI/2 saa X=PI-X
;Y=X/3, Z=Y^2
;SIN(Y)=Y(((((Z+K1)Z+K2)Z+K3)Z+K4)Z+K5)/K5
;K1=-110 K2=7920 K3=-332640
;K4=6652800 K5=-39916800
;SIN(X)=4(.75*SIN(Y)-SIN(Y)^3)
SIN: EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
SINC: CALL ACPI ;AC'=2PI
INC L
EXX
LD A,L ;Hvis tallet er mindre
CP EXPN-20 ;end 1E-7 saa returner
JP C,SIN7
PUSH BC ;Er ABS(AC)>2PI
RES 7,B
CALL CMP
POP BC
CALL NC,MOD ;Ja => AC=AC MOD 2PI
SIN1A: BIT 7,B ;Hvis AC<0 saa laeg
JR Z,SIN2 ;2PI til AC
CALL FPADD
SIN2: EXX ;AC'=PI
DEC L
EXX
CALL CMP ;Er AC>PI?
PUSH AF ;Gem flag som fortegn
JR C,SIN3 ;Nej => SIN3
CALL FPSUB ;AC=AC-PI
SIN3: EXX ;AC'=PI/2
DEC L
EXX
CALL CMP ;Er AC>PI/2?
JR C,SIN4 ;Nej => SIN4
EXX ;AC=PI-AC
INC L
CALL FPSUB
SIN4: LD A,L ;Hvis tallet er mindre
CP EXPN-20 ;end 1E-7 saa returner
JR C,SIN7A
EXX ;AC=AC/3
LD BC,02AAAH
LD DE,0AAAAH
LD HL,0AA7FH
CALL FPMUL
PUSH IX
LD IX,SINK-6
LD A,5
CALL COMSER
POP IX
CALL EQUAL ;Gem i AC'
CALL FPMUL ;Udregn SIN(X)^3
CALL FPMUL
PUSH BC ;Gem paa stakken
PUSH DE
PUSH HL
EXX
CALL EQUAL ;Udregn .75*SIN(X)
DEC L
DEC L
EXX
DEC L
CALL FPADD
EXX ;Hent SIN(X)^3
POP HL
POP DE
POP BC
EXX
CALL FPSUB ;Traek det fra
INC L ;Gang med 4
INC L
SIN7A: POP AF ;Indsaet fortegn
INC L
DEC L
JR Z,SIN7
JR C,SIN7
LD A,B
XOR SIGN
LD B,A
SIN7: OR A
JP ADD10 ;Hent AC'
;Konstanter for udregning af SINUS.
SINK: DW 0DC00H,00000H,00087H ;K1
DW 07780H,00000H,0008DH ;K2
DW 0A26CH,00000H,00093H ;K3
DW 04B07H,00000H,00097H ;K4
DW 09845H,04000H,0009AH ;K5
;TITALS LOGARITME.
;LOG(X) beregnes af LN(X)/LN(10).
LOG: CALL LN
RET C
EXX
PUSH BC
PUSH DE
PUSH HL
LD BC,05E5BH ;1/LN(10)
LD DE,0D8A9H
LD HL,0367FH
CALL FPMUL
JP ADD10
;NATURLIGE LOGARITME.
;LN(X) beregnes paa flg. maade:
;X=Y*2^N, 1<=Y<2
;Z=Y*SQR(2)/2
;U=(Z-1)/(Z+1), V=U^2
;R=U((((((V+K1)V+K2)V+K3)V+K4)V+K5)V+K6)/K6
;Kn=13/(13-2n)
;LN(X)=2*R+LN(2)/2+N*LN(2)
LN: INC L ;Er AC nul?
DEC L
SCF ;Indiker fejl
RET Z ;Ja => Returner
BIT 7,B ;Negativ?
RET NZ ;Ja => Returner
EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
LD BC,03504H ;AC'=SQR(2)/2
LD DE,0F333H
LD HL,0FB80H
EXX
LD A,L ;Udregn N
LD L,EXPN+1 ;Udregn Y
SUB L
PUSH AF ;Gem N
CALL FPMUL ;Udregn Z
EXX ;Udregn U
CALL AC1
EXX
CALL FPSUB
PUSH BC
PUSH DE
PUSH HL
EXX
INC L
CALL FPADD
EXX
POP HL
POP DE
POP BC
CALL FPDIV
PUSH IX ;Udregn LN(Z)
LD IX,LNK-6
LD A,6
CALL COMSER
POP IX
INC L ;Laeg LN(2)/2 til
EXX
CALL ACLN2
DEC L
EXX
CALL FPADD
POP AF
PUSH BC ;Gem resultat
PUSH DE
PUSH HL
LD L,A ;Udregn N*LN(2)
LD H,0
JR NC,LN1
DEC H
LN1: CALL FLOAT
EXX
INC L
CALL FPMUL
EXX
POP HL ;Hent resultat
POP DE
POP BC
CALL FPADD ;Adder
LD A,L
CP EXPN-25 ;LN(X)<3E-8 => LN(X)=0
CALL C,ZERO
JP ADD10 ;Hent AC'
;Konstanter for udregning af LN.
LNK: DW 01745H,0D174H,05D81H ;K1
DW 038E3H,08E38H,0E481H ;K2
DW 06DB6H,0DB6DH,0B781H ;K3
DW 02666H,06666H,06682H ;K4
DW 00AAAH,0AAAAH,0AB83H ;K5
DW 05000H,00000H,00084H ;K6
;POTENSOPLOEFTNING.
;X^Y beregnes af EXP(Y*LN(X)).
PWR: LD A,L
OR A
RET Z
CALL LN
RET C
CALL FPMUL
RET C
;EXPONENTIALFUNKTIONEN.
;Hvis X<0 saa udregnes EXP(X)=1/EXP(-X).
;EXP(X) beregnes paa flg. maade:
;EXP(X)=2^Y, Y=X/LN(2)
;2^Y=2^INT(Y)*2^Z, Z=FRAC(Y)
;2^Z udregnes af:
;2^Z=(((((((Z+K1)*Z+K2)*Z)2+K3)....)*Z+K7)/K7
;K1=6.6042604723 K2=62.027114868
;K3=444.01034843 K4=2563.5667136
;K5=11095.090786 K6=32013.685271
;K7=46185.984492
EXP: EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
CALL ACLN2 ;AC'=LN(2)
EXX
OR A ;Gem fortegn
BIT 7,B
PUSH AF
RES 7,B ;Goer positivt
CALL FPDIV ;Udregn Y
LD A,L ;Er Y>128?
CP EXPN+8
JP NC,EXP4 ;Ja => EXP4
CALL EQUAL ;AC'=Y
CALL FRAC ;Udregn Z=FRAC(Y)
EXX ;Udregn INT(Y)
CALL FIX
LD A,L
PUSH AF ;Gem INT(Y)
EXX
EXP1: PUSH IX ;Udregn 2^Z
LD IX,EXPK-6
LD A,7
CALL CALCS
POP IX
EXP3: POP AF ;Hent 2^INT(Y)
ADD A,L ;Udregn 2^Z*2^INT(Y)
LD L,A
JR NC,EXP6 ;Ikke overflow => EXP6
EXP4: POP AF ;Juster stakken
SCF ;Indiker overflow
EXP5: JP ADD10 ;Hent AC'
EXP6: POP AF ;Hent fortegn
JR Z,EXP5 ;Positivt => EXP5
EXX ;Tag den reciprokke
CALL AC1
CALL FPDIV
JR EXP5
;Konstanter for udregning af EXP.
EXPK: DW 05356H,01A0EH,0DE83H ;K1
DW 0781BH,0C3FFH,0FB86H ;K2
DW 05E01H,05318H,0F189H ;K3
DW 02039H,01142H,0418CH ;K4
DW 02D5CH,05CF6H,0DF8EH ;K5
DW 07A1BH,05EDBH,0CD8FH ;K6
DW 03469H,0FC07H,0E590H ;K7
;ARCCUS TANGENS.
;Hvis X>1 udregnes ATN(X)=PI/2-ATN(1/X).
;Til beregning af ATN(X) bruges:
;Y=X^2, A=PI/24,
;ATN(X)=X(((((Y+K1)*Y+K2)*Y+K3)*Y+K4)*Y+K5)/K5,
;hvor 0<=X<A og
;K1=-11/9 K2=11/7 K3=-11/5 K4=11/3 K5=-11
;X bestemmes til at ligge i et af interv.:
;1. X<TAN(A)
;2. TAN(A)<=X<TAN(3*A) ,K=2*A
;3. TAN(3*A)<=X<TAN(5*A) ,K=4*A
;4. X>=TAN(5*A) ,K=6*A
;Hvis X er i foerste interv. bruges formelen
;alene, men ellers bruges:
;Y=(X-TAN(K))/(1+X*TAN(K))
;ATN(X)=K+ATN(Y)
ATN: LD A,L
OR A
RET Z
EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
PUSH IX
CALL AC1 ;AC'=1
EXX
XOR A ;Nulstil flagbyte
BIT 7,B ;Er AC positiv?
JR Z,ATN1 ;Ja => ATN1
INC A ;Saet negativflag
RES 7,B ;AC=ABS(AC)
ATN1: PUSH AF ;Gem flag
CALL CMP ;Er AC>1
JR C,ATN2 ;Ja => ATN2
EXX ;AC=1/AC
CALL FPDIV
POP AF ;Saet reciprokflag
SET 7,A
PUSH AF
ATN2: EXX
LD BC,006CFH
LD DE,0E98EH
LD HL,04A7EH
EXX
CALL CMP ;Er AC<TAN(PI/24)?
JR NC,ATN3 ;Nej => ATN3
CALL ARCTAN ;Udregn ATN(X)
JR ATN6
ATN3: LD IX,ATNK-18 ;Peg IX til skalerings-
LD A,2 ;konstanter
ATN4: EX AF,AF' ;Gem taeller
EXX
LD DE,18 ;Peg til naeste saet
ADD IX,DE
CALL GETCIX ;Hent oeverste endepkt.
EXX
CALL CMP ;Er X i dette interval?
JR C,ATN5 ;Ja => ATN5
EX AF,AF' ;Hent taeller
DEC A ;Faerdig?
JR NZ,ATN4 ;Nej => ATN4
EXX ;Juster IX
LD DE,12
ADD IX,DE
EXX
ATN5: EXX
CALL GTNCIX ;Hent TAN(K)
SET 7,B ;Udregn X-TAN(K)
CALL FPADD
PUSH BC ;Gem resultat
PUSH DE
PUSH HL
CALL GETCIX ;Hent TAN(K)
CALL FPMUL ;Udregn X*TAN(K)
EXX
CALL AC1 ;Laeg 1 til
CALL FPADD
EXX ;Gem i AC'
POP HL ;Hent forrige resultat
POP DE
POP BC
CALL FPDIV ;Udregn Y
PUSH IX ;Udregn ATN(Y)
CALL ARCTAN
POP IX
EXX
CALL GTNCIX ;Hent K
CALL FPADD ;Udregn K+ATN(Y)
ATN6: POP AF ;Hent flagbyte
RLA ;Var X>1?
JR NC,ATN7 ;Nej => ATN7
PUSH AF ;Gem flagbyte
EXX ;Udregn PI/2-ATN(X)
CALL ACPI
DEC L
CALL FPSUB
POP AF ;Hent flagbyte
ATN7: POP IX ;Hent IX
BIT 1,A ;Var X<0?
JR Z,ATN8 ;Nej => ATN8
SET 7,B ;Resultat negativt
ATN8: OR A
JP ADD10 ;Hent AC'
;Konstanter til skalering af X under beregning
;af ATN.
ATNK: DW 05413H,0CCCFH,0E77FH ;TAN(3*A)
DW 00930H,0A2F4H,0F67FH ;TAN(2*A)
DW 0060AH,091C1H,06A7FH ;2*A
DW 0446FH,08A9EH,0B580H ;TAN(5*A)
DW 013CDH,03A2CH,08280H ;TAN(4*A)
DW 0060AH,091C1H,06A80H ;4*A
DW 00000H,00000H,00081H ;TAN(6*A)
DW 0490FH,0DAA2H,02180H ;6*A
;Konstanter for beregning af ATN.
ARCTK: DW 09C71H,0C71CH,07281H ;K1
DW 04924H,09249H,02581H ;K2
DW 08CCCH,0CCCCH,0CD82H ;K3
DW 06AAAH,0AAAAH,0AB82H ;K4
DW 0B000H,00000H,00084H ;K5
;Udregn taylorraekken for ARCCUS TANGENS.
ARCTAN: LD IX,ARCTK-6
LD A,5
;COMSER udregner en potensraekke af formen:
;T=X*((((X^2+K1)*X^2+K2)....)*X^2+Kn)/Kn,
;hvor X er i AC, n er i A, og adressen paa
;konstanterne (minus 6) i IX.
COMSER: PUSH BC ;Gem X
PUSH DE
PUSH HL
PUSH AF ;Gem laengde
CALL EQUAL ;Udregn Z=X^2
CALL FPMUL
POP AF ;Hent laengde
CALL CALCS ;Udregn raekken
EXX ;Hent X
POP HL
POP DE
POP BC
JP FPMUL ;Gang med X
;CALCS udregner en potensraekke af formen:
;U=(((((Z+K1)*Z+K2)*Z+K3)....)*Z+Kn)/Kn,
;hvor Z er i AC, n er i A, og adressen paa
;konstanterne (minus 6) i IX.
CALCS: EXX ;Gem Z i AC'
CALL AC1 ;Start med resultat=1
CALC1: PUSH AF ;Gang med Z
CALL FPMUL
POP AF
PUSH AF
EXX
PUSH BC ;Gem Z
PUSH DE
PUSH HL
CALL GTNCIX ;Hent naeste konstant
CALL FPADD ;Laeg til resultat
EXX ;Hent Z
POP HL
POP DE
POP BC
EXX
POP AF ;Faerdig?
DEC A
JR NZ,CALC1 ;Nej => CALC1
EXX
CALL GETCIX
EXX
JP FPDIV
;Saet AC lig den konstant IX peger paa.
GTNCIX: LD DE,6
ADD IX,DE
GETCIX: LD C,(IX+0)
LD B,(IX+1)
LD E,(IX+2)
LD D,(IX+3)
LD L,(IX+4)
LD H,(IX+5)
RET
;Saet AC lig 2*PI.
ACPI: LD BC,0490FH
LD DE,0DAA2H
LD HL,02182H
RET
;Saet AC lig LN(2).
ACLN2: LD BC,03172H
LD DE,017F7H
LD HL,0D280H
RET
;FLOATING POINT EQUAL.
EQUAL: PUSH BC
PUSH DE
PUSH HL
EXX
POP HL
POP DE
POP BC
RET
;FLOATING POINT TIL 16-BIT INTEGER MED
;2'S COMPLEMENT FORTEGN.
FIX: OR A
BIT 7,L ;Exponent<0?
JR Z,FIX4 ;Ja => FIX4
BIT 7,B ;Gem fortegn
EX AF,AF'
SET 7,B ;Saet MSB
FIX1: LD A,EXPN+15 ;Test exponent
CP L
RET C ;EXP>15 => overflow
JR Z,FIX2 ;EXP=15 => FIX2
CALL SRIGHT ;EXP<15 => roter til
INC L ;hoejre og laeg 1 til
JR FIX1 ;exponent
FIX2: CALL SRIGHT ;Roter til hoejre
EX AF,AF' ;Negativt fortegn?
JR Z,FIX3 ;Nej => INT2
LD HL,0 ;Tag 2's complement
SBC HL,BC
OR A ;Nulstil carry
RET
FIX3: LD H,B ;Hent tallet
LD L,C
RET
FIX4: LD HL,0 ;Underflow
RET
;16-BIT INTEGER MED 2'S COMPLEMENT FORTEGN
;TIL FLOATING POINT.
FLOAT: LD A,H ;Er HL=0?
OR L
JP Z,ZERO ;Ja => ZERO
BIT 7,H ;Er HL negativ?
JR Z,FLT1 ;Nej => FLT1
EX DE,HL ;Tag 2's complement
LD HL,0
OR A
SBC HL,DE
FLT1: EX AF,AF' ;Gem fortegn i F'
LD B,H ;Saet mantissa
LD C,L
LD DE,0
LD HL,EXPN+16 ;Saet exponent
FLT2: BIT 7,B ;Normaliser
JR NZ,FLT3
CALL SLEFT
DEC L
JR FLT2
FLT3: EX AF,AF' ;Negativt?
RET C ;Ja => Retur
RES 7,B ;Positivt
RET
;FLYDENDE TAL TIL TEKSTSTRENG.
;Resultatet afleveres i den buffer IX peger
;paa, og er afsluttet med et 0.
;Udskriftens format afgoeres af H' og L'.
;Register L':
;Bit 0 Udskriftstype
; 0 - Fastkomma notation
; 1 - Exponentiel notation
;Bit 2-1 Fortegnsformat
; 00 - Intet fortegn
; 01 - AC>=0: Intet fortegn
; AC<0: "-"
; 10 - AC>=0: " "
; AC<0: "-"
; 11 - AC>=0: "+"
; AC<0: "-"
;Bit 3 Decimaldelsformat
; 0 - Kun betydende cifre
; 1 - Skriv alle cifre
;Bit 4 Heltalsdelformat
; 0 - Kun betydende cifre
; 1 - Blanktegn foer betydende cifre
;Register H':
;Bit 3-0 Decimalfeltets laengde (0-15)
;Bit 7-4 Heltalsfeltets laengde (1-15)
; Bruges kun hvis bit 0 i L' er 0
FSTRR: EXX
LD A,L ;Gem format i A og A'
EX AF,AF'
LD A,H
EXX
JR OUTN1
;FLYDENDE TAL TIL TEKSTSTRENG.
;Formatet efterfoelger kaldet som to bytes, der
;har samme betydning som L' henholdsvis H' ved
;kald af FSTRR.
FSTRS: EX (SP),IX
LD A,(IX+0) ;Gem format i A og A'
INC IX
EX AF,AF'
LD A,(IX+0)
INC IX
EX (SP),IX
OUTN1: PUSH IX ;Gem IX,IY,AC,AC'
PUSH IY
PUSH BC
PUSH DE
PUSH HL
EXX
PUSH BC
PUSH DE
PUSH HL
EXX
LD IY,-13 ;Opret en 13 bytes
ADD IY,SP ;buffer paa stakken
LD SP,IY
EXX
LD E,A ;Gem formatet
EX AF,AF'
LD D,A
PUSH DE
EXX
INC L ;Er AC nul?
DEC L
JR NZ,DIGITS ;Nej => DIGITS
POP DE ;Hent formatet
DZERO: LD (IY+0),L ;Marker bufferslut
JP OUTM
DIGITS: PUSH BC ;Gem BC
RES 7,B ;Goer AC positiv
LD A,L ;Hent exponent
EXX
;Udregn titalsexponenten udfra totalsexponenten
;paa foelgende maade:
;E10=INT(E2*LOG(2))=INT((E2*77+5)/256)
LD H,0 ;HL=toexponent
SUB EXPN
JR NC,SC1
DEC H
SC1: LD L,A
PUSH HL ;HL=HL*77+5
ADD HL,HL
ADD HL,HL
PUSH HL
ADD HL,HL
LD D,H
LD E,L
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,DE
POP DE
ADD HL,DE
POP DE
ADD HL,DE
LD DE,5
ADD HL,DE
LD A,H ;A=INT(HL/256)
CP -39
JR NZ,SC2
INC A
SC2: LD (IY+0),A ;Gem tiexponent
NEG ;Multiplicer AC med
CALL TENF ;10^-tiexponent
LD A,L ;Er AC<1?
CP EXPN+1
JR NC,SC3 ;Nej => SC3
DEC (IY+0) ;Tiexponent-1
CALL MUL10 ;AC=AC*10
SC3: SET 7,B
LD A,EXPN+4
SUB L
LD L,0
JR Z,DIGI1
SC4: CALL SRIGHT
RR L
DEC A
JR NZ,SC4
DIGI1: LD A,(IY+0) ;Hent tiexp.
LD (IY+0),0 ;Marker bufferstart
PUSH IY ;Gem IY
PUSH AF ;Gem tiexp.
LD A,12 ;Udregn 12 cifre
DIGI2: EX AF,AF' ;Gem taeller
LD A,B
RRA
RRA
RRA
RRA
AND 0FH
ADD A,'0'
INC IY
LD (IY+0),A
LD A,B
AND 0FH
LD B,A
PUSH BC ;Gang AC med 10
PUSH DE
PUSH HL
SLA L
CALL LEFT
SLA L
CALL LEFT
EX DE,HL
EX (SP),HL
ADD HL,DE
POP DE
EX (SP),HL
ADC HL,DE
EX DE,HL
POP HL
EX (SP),HL
ADC HL,BC
LD B,H
LD C,L
POP HL
SLA L
CALL LEFT
EX AF,AF' ;Hent taeller
DEC A ;Faerdig?
JR NZ,DIGI2 ;Nej => DIGI2
POP AF ;Hent tiexp.
POP IY ;Hent IY,BC
POP BC
INC IY ;Peg til foerste ciffer
LD C,A ;Gem titalsexp. i C
ROUND: POP DE ;Hent format
LD A,E ;Udregn nummeret paa
AND FWIDTH ;det ciffer der skal
INC A ;afrundes fra
BIT 0,D
JR NZ,ROU1
ADD A,C
JP M,DZERO ;Neg. => Udskriv 0
ROU1: CP 12 ;Max. nummer 11
JR C,ROU2
LD A,11
ROU2: PUSH IY ;Udregn adressen paa
POP HL ;det ciffer der skal
ADD A,L ;afrundes
LD L,A
JR NC,ROU3
INC H
ROU3: LD A,(HL) ;Hent ciffer
LD (HL),0 ;Marker bufferslut
CP '5' ;Afrunding?
JR C,ROU5 ;Nej => ROU5
ROU4: DEC HL ;Tag forrige ciffer
LD A,(HL)
OR A ;Bufferstart?
JR Z,ROU6 ;Ja => ROU6
INC A ;Laeg 1 til ciffer
LD (HL),A
CP '9'+1 ;Var ciffer '9'?
JR C,OUTM ;Nej => OUTM
LD (HL),0 ;Marker bufferslut
JR ROU4
ROU5: DEC HL ;Tag forrige ciffer
LD A,(HL)
SUB '0' ;Er det '0'?
JR NZ,OUTM ;Nej => OUTM
LD (HL),A ;Marker bufferslut
JR ROU5
ROU6: INC HL ;Tallet var 9999...
LD (HL),'1' ;Lav om til 10000...
INC HL
LD (HL),0
INC C ;Laeg 1 til tiexp.
OUTM: LD A,(IY+0) ;Er tallet 0?
OR A
JR NZ,OM1 ;Nej => OM1
LD B,A ;Positivt fortegn
LD C,A ;Tiexp = 0
OM1: BIT 0,D ;Exponentielt?
JR NZ,OM6 ;Ja => OM6
LD A,E ;Udregn det antal
AND IWIDTH ;blanktegn der skal
RRCA ;udskrives inden tallet
RRCA
RRCA
RRCA
DEC A
BIT 2,D
JR NZ,OM2
BIT 1,D
JR Z,OM3
BIT 7,B
JR Z,OM3
OM2: DEC A
OM3: BIT 7,C
JR NZ,OM4
SUB C
OM4: OR A ;Negativt?
SCF ;Indiker fejl
JP M,POPALL ;Ja => POPALL
BIT 4,D ;Blanktegn?
JR Z,OM6 ;Nej => OM6
LD H,A ;Gem blanktegn
INC H
OM5: DEC H
JR Z,OM6
LD A,' '
CALL STOA
JR OM5
OM6: BIT 7,B ;Gem fortegn
JR Z,OM7
LD A,'-'
BIT 2,D
JR NZ,OM8
BIT 1,D
JR NZ,OM8
JR OM9
OM7: BIT 2,D
JR Z,OM9
LD A,' '
BIT 1,D
JR Z,OM8
LD A,'+'
OM8: CALL STOA
OM9: BIT 0,D ;Exponentielt?
JR Z,OM10 ;Nej => OM10
LD H,C ;Gem tiexp. i H
LD C,0 ;tiexp. = 0
OM10: BIT 7,C ;Er tiexp.>=0?
JR Z,OM11 ;Ja => OM11
CALL STOZ ;Gem '0'
JR OM12
OM11: CALL STODIG ;Gem de cifre der
DEC C ;staar foer kommaet
JP P,OM11
OM12: LD A,E ;Skal der cifre efter
AND FWIDTH ;kommaet?
JR Z,OM15 ;Nej => OM15
LD E,A
CALL MORED ;Er der flere cifre?
JR Z,OM15 ;Nej => OM15
LD A,'.' ;Gem '.'
CALL STOA
OM13: INC C ;Gem ubetydende nuller
JR Z,OM14
CALL STOZ
DEC E
JR NZ,OM13
OM14: DEC E ;Gem betydende cifre
JP M,OM15
CALL STODIG
CALL MORED
JR NZ,OM14
OM15: BIT 0,D ;Exponentielt?
JR Z,POPA1 ;Nej => POPA1
LD A,'E' ;Gem 'E'
CALL STOA
LD A,'+' ;Gem fortegn
BIT 7,H
JR Z,OEX1
LD A,H
NEG
LD H,A
LD A,'-'
OEX1: CALL STOA
LD A,H ;Udregn 2-cifret exp.
LD B,'0'-1
OEX2: INC B
SUB 10
JR NC,OEX2
ADD A,10+'0'
LD (IX+0),B ;Gem exponent
INC IX
CALL STOA
POPA1: OR A ;Nulstil carry
POPALL: EX AF,AF' ;Gem status
LD (IX+0),0 ;Marker bufferslut
LD HL,13 ;Fjern talbuffer
ADD HL,SP
LD SP,HL
POP HL ;Hent AC',AC,IY,IX
POP DE
POP BC
EXX
POP HL
POP DE
POP BC
POP IY
POP IX
EX AF,AF' ;Hent status
RET
;Gem et ciffer i bufferen.
STODIG: LD A,(IY+0) ;Hent ciffer
INC IY
OR A ;Bufferslut?
JR NZ,STOA ;Nej => STOA
DEC IY ;Juster
STOZ: LD A,'0' ;Gem '0'
STOA: LD (IX+0),A
INC IX
RET
;Undersoeg om der er flere cifre.
MORED: BIT 3,D
RET NZ
LD A,(IY+0)
OR A
RET
;Multiplicer AC med 10^A.
TENF: PUSH AF ;Gem AF
OR A ;Positiv exponent?
JP P,TF1 ;Ja => TF1
NEG ;A=ABS(A)
TF1: PUSH AF ;Gem flag
SRL A ;A=INT(A/4)
SRL A
LD HL,-6 ;Udregn offset til
LD DE,6 ;konstant nummer A
INC A
TF2: ADD HL,DE
DEC A
JR NZ,TF2
EX DE,HL
PUSH IX ;Gem IX
LD IX,CON10 ;Hent konstant
ADD IX,DE
CALL GETCIX
POP IX ;Hent IX
POP AF ;Hent exponent
AND 3 ;Juster faktor
TF3: JR Z,TF4
PUSH AF
CALL MUL10
POP AF
DEC A
JR TF3
TF4: POP AF ;Hent exponent
OR A ;Positiv?
JP P,FPMUL ;Ja => Multipicer
EXX ;Nej => Divider
JP FPDIV
;Tier potens konstanter for konvertering.
CON10: DW 00000H,00000H,00081H ;1E+00
DW 01C40H,00000H,0008EH ;1E+04
DW 03EBCH,02000H,0009BH ;1E+08
DW 0684DH,0A510H,000A8H ;1E+12
DW 00E1BH,0C9BFH,004B6H ;1E+16
DW 02D78H,0EBC5H,0ACC3H ;1E+20
DW 053C2H,01BCEH,0CDD0H ;1E+24
DW 0013FH,03978H,0F9DEH ;1E+28
DW 01DC5H,0ADA8H,02BEBH ;1E+32
DW 04097H,0CE7BH,0C9F8H ;1E+36
;AC=ABS(AC)*10.
MUL10: LD A,L
OR A
RET Z
SET 7,B
PUSH BC
PUSH DE
LD A,H
CALL SRIGHT
CALL SRIGHT
ADD A,H
LD H,A
EX (SP),HL
ADC HL,DE
EX DE,HL
POP HL
EX (SP),HL
ADC HL,BC
LD B,H
LD C,L
POP HL
JR NC,M10A
CALL RIGHT
INC L
SCF
RET Z
M10A: LD A,L
ADD A,3
LD L,A
RES 7,B
RET
;ASCII TIL FLOATING POINT.
CNVN: EXX ;Gem AC'
PUSH BC
PUSH DE
PUSH HL
LD BC,0 ;Nulstil flag
EXX
CALL ZERO ;Nulstil AC
LD A,(IX+0) ;Hent foerste karakter
CP '+' ;Plus?
JR Z,CNV1 ;Ja => CNV1
DEC IX
CP '-' ;Minus?
JR NZ,CNV1 ;Nej => CNV1
EXX ;Saet minusflag
SET 7,B
EXX
INC IX
CNV1: INC IX ;Hent naeste karakter
LD A,(IX+0)
CP '.' ;Decimalpunkt?
JR NZ,CNV2 ;Nej => CNV2
EXX ;Er det det foerste?
BIT 6,B
SCF
JP NZ,CNV6 ;Nej => FEJL
SET 6,B ;Ja => saet flag
EXX
JR CNV1
CNV2: CP 'E' ;Exponentnotation?
JR Z,CNV4 ;Ja => CNV4
CALL DIGTST ;Er det et ciffer?
JR NC,CNV5 ;Nej => CNV5
EX AF,AF' ;Gang resultat med 10
CALL MUL10
JR C,CNV6A
EX AF,AF'
EXX ;Laeg det nye ciffer
PUSH BC ;til
LD L,A
LD H,0
CALL FLOAT
CALL FPADD
EXX
POP BC
JR C,CNV6A
BIT 6,B ;Er decimalflag sat?
JR Z,CNV3 ;Nej => CNV3
DEC C ;Traek 1 fra tiexp.
CNV3: EXX
JR CNV1
CNV4: CALL MFACT ;Gang med titalsfaktor
JR C,CNV6 ;Overflow => CNV6
EXX
INC IX ;Hent naeste karakter
LD A,(IX+0)
CP '+' ;Plus?
JR Z,CNV4A ;Ja => CNV4A
CP '-' ;Minus?
JR NZ,CNV4B ;Nej => CNV4B
SET 5,B ;Saet minusflag
CNV4A: INC IX
CNV4B: CALL GDTST ;Er der et ciffer?
CCF ;Saet carry hvis ikke
CNV6A: JR C,CNV6 ;Nej => CNV6
LD C,A ;Gem i C
INC IX ;Er der et mere?
CALL GDTST
JR NC,CNV4C ;Nej => CNV4C
INC IX ;Gang forrige ciffer
LD D,A ;med 10 og laeg det
LD A,C ;nye til
ADD A,A
ADD A,A
ADD A,C
ADD A,A
ADD A,D
LD C,A
CNV4C: BIT 5,B ;Negativt?
JR Z,CNV4D ;Nej => CNV4D
LD A,C
NEG
LD C,A
CNV4D: EXX
CNV5: CALL MFACT ;Gang med titalsfaktor
JR C,CNV6 ;Overflow => CNV6
EXX ;Negativt?
BIT 7,B
EXX
JR Z,CNV6 ;Nej => CNV6
SET 7,B ;Saet minusflag i AC
CNV6: JP ADD10 ;Hent AC'
;Gang tallet i AC med 10^C'
MFACT: EXX
LD A,C
ADD A,EXPN
CP -37+EXPN ;Tiexp.<-37?
RET C ;Ja => Retur
CP 38+EXPN ;Tiexp.>37?
CCF
RET C ;Ja => Retur
PUSH BC ;Gem BC
LD A,C ;Hent tiexponent
CALL TENF ;Mul. med 10^tiexp.
EXX ;Hent BC
POP BC
EXX
RET
;Saet carry hvis karakteren i A er et ciffer.
GDTST: LD A,(IX+0)
DIGTST: SUB '0'
CCF
RET NC
CP 10
RET
;Saet AC lig 1.
AC1: LD BC,00000H
LD DE,00000H
LD HL,00081H
RET
;------------END OF MATH48------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment