witam i podziwiam
nie chce mi się wyciągać ZX z szafki i znowu gapić się w ten zielony monitor
Dzięki Sinclairowi za Spectruma ! gdyby nie ten komputer to nie znałbym się na mikroelektronice. Rok temu przesiadłem się na PCta, i przekładam swoje programy na intelowskie mnemoniki
'25 * 255
ORG 0 ; jeśli to "samoróba"
ORG 32768 ; jeśli to ZX Spectrum :)
LD HL, 25
LD DE, 0
LD A, 255
LD B, 8 ; 8 przebiegów pętli dla 8-io bitowego mnożnika
NextBit:
RRA ; test bitu 0
JC Nieparzyste
ADD HL, HL ; A było parzyste : A=A/2 HL=2HL
JR dalej
Nieparzyste:
ADD A,A ; A=A-1 DE=DE+HL
EX DE,HL
ADD HL,DE
EX DE,HL
Dalej:
DJNZ NextBit
ADD HL,DE
;wynik w HL
jest to szybki algorytm mnożenia - liczba przebiegów pętli jest liniowo zależna od ilości bitów mnożnej
na początku mnożnik wpisujemy do wyniku i zaczynamy z koksem:
jeśli mnożna jest parzysta to mnożymy wynik przez 2, a mnożną dzielimy przez 2
w przeciwnym razie aktualny wynik dodajemy do podręcznej pamięci (DE) a mnożną zmniejszamy o jeden
powtażamy to 8 razy (bo mnożymy przez liczbę ośmio-bitową) i na końcu dodajemy do wyniku tą podręczną pamięć
może po kodzie tego nie widać że zmniejszam mnożną o 1, ale patrz:
RRA - dzieli A przez 2 i jeśli A było nieparzyste (21/2 = 10) to flaga C się ustawia i program skacze do rozkazu ADD A,A (10+10) czyli A=20 - więc A jest mniejsze o 1 niż poprzednio
tego algorytmu mnożenia użyłem do obliczania silnii na PC i wyniki są zadowalające (liczenie w kodzie BCD amd 2800+):
1000! - 0.078s 2568 cyfr
10000! - 13s 35660 cyfr
50000! - 7min 213237 cyfr
75000! - 19min 333061 cyfr
podczas gdy Z80 @4MHz obliczał 1000! chyba w 30minut :d ale szybciej od Amigi 600 :d:d
można i tak:
LD HL,0
LD DE, mnożna
LD B,mnożnik
loop:
ADD HL,DE
DJNZ loop
tylko nie wiem po co stos do tego pakować ? To ma działać jak winapi?
PUSH mnożna
PUSH mnożnik
CALL pomnóż
POP wynik
POP HL ;adres powrotny
EXX ; wymiana rejestrów HL DE i BC na "zapasowe"
POP HL
POP DE
LD A,E
[mnożenie]
PUSH HL ;wynik na stos
EXX ; oddaj stare rejestry
JP (HL) ; pseudo RET
teraz coś dla PCmaniaków: mnożenie długich liczb po intelowsku
CHAR a[0xFFFFF], b[0xFFFFF] /* 2097150 cyfr dla wyniku */
'zerowanie tabel
RtlZeroMemory(&a, 0xFFFFF)
RtlZeroMemory(&b, 0xFFFFF)
'mnożymy 40000 * 7
a[0]=7
UINT BC, LenA /* LenA to ilość bajtów wyniku */
BC = 40000
LenA = 1
'start
'NASM assembler IBasic PRO
_asm
MOV eax,[$BC] ;eax = 40000
LoopDo:
MOV ebx,eax
AND ebx,1
JZ RLCA ; jump if BC & 1 = 0
DEC eax ; mul--
PUSH eax
;*************************
AddAtoB:
MOV ecx,[LenA] ; Counter
MOV edx,$b
MOV ebx,$a
CLC ; Clear Carry
LaddAB:
MOV al,[edx] ; Get 2 bytes from b[n]
ADC al,[ebx] ; Add a[n]
DAA ; BCD correction
MOV [edx],al ; Store in b[n]
INC edx
INC ebx
LOOP LaddAB ; 'next n'
JNC Lrlcaexit
INC dword[edx] ; if Carry then add one digit
JMP Lrlcaexit
;*************************
RLCA:
SHR eax,1 ; mul = mul >> 1
PUSH eax
;*************************
MOV ecx,[LenA] ; Counter
MOV ebx,$a
CLC ; Clear Carry
Lrlca:
MOV al,[ebx] ; Get 2 bytes from a[n]
ADC al,al ; bytes *2 + Carry
DAA ; BCD correction
MOV [ebx],al ; Store in a[n]
INC ebx ; n++
LOOP Lrlca ; 'next n'
JNC Lrlcaexit
INC dword[ebx] ; if Carry then add one digit
INC dword[$LenA] ; and inc number of digits
;*************************
Lrlcaexit:
POP eax
CMP eax,1
JA LoopDo ; until BC>1
;*************************
AddBtoA:
MOV ecx,[LenA] ; Counter
MOV edx,$a
MOV ebx,$b
CLC ; Clear Carry
LaddBA:
MOV al,[edx] ; Get 2 bytes from a[n]
ADC al,[ebx] ; Add bytes from b[n]
DAA ; BCD correction
MOV [edx],al ; Store in a[n]
INC edx ; n++
INC ebx
LOOP LaddBA ; 'next n'
JNC LaddBAexit
INC dword[edx] ; if Carry then add one digit
INC dword[$LenA] ; and inc number of digits
LaddBAexit:
_endasm