Große Fibonacci // NASM // Linux 64-bit

Pascal, Basic und andere nicht aufgelistete
Antworten
osculumobscenum
Beiträge: 25
Registriert: Do Okt 31, 2013 9:03 pm

Große Fibonacci // NASM // Linux 64-bit

Beitrag von osculumobscenum » Fr Feb 09, 2024 12:04 pm

Hallo zusammen,

ich hab neulich ein wenig experimentiert, und zwar mit dem Versuch, größere Zahlen zu "behandeln", als sie eigentlich in die Variablen passen. Das Ganze mit dem NASM, unter Linux (Debian) 64 bit. Dazu bietet sich am einfachsten die Fibonacci-Serie an.
Ich hab auch überlegt, ob ich das dann in euren Fibonacci-Benchmark-Thread stelle, aber ich war mir nicht sicher, ob das wirklich vergleichbar ist. Daher hier einzeln, "zur Inspiration". ;-)
Ich habe drei Arrays mit einzelnen Bytes gemacht, mit jeweils 10.000 Stellen. Dh. so viele Stellen kann die Zahl eigentlich haben.
Der unten aufgeführte Quellcode berechnet die ersten 5000 Fibonacci-Zahlen, und gibt davon (wenn ich mich noch recht erinnere) die letzten 10 aus. Beides ist natürlich im Sourcecode änderbar. Assemblier- und Linkanweisung im Code.

Code: Alles auswählen

; fiborgr.asm
; 
; errechnet RICHTIG GROSSE Fibonacci's und gibt jene aus.
; nasm -f elf64 fiborgr.asm
; ld -s -o fiborgr fiborgr.o      "warum -s ? -s "strippt" die Debug-Infos weg. Wenn man debuggen will, lieber ohne -s"

[bits 64]

SECTION .data

_overflow_msg db '*** Series overflown.',0ah
len_overflow_msg equ $-_overflow_msg
_one db '1 '
_endl db 10
_leerz db 0        
ziffer db 0

SECTION .bss
 f1array  :  resb 10000 	; drei arrays, aus einzelnen Bytes (Ziffern).
 f2array  :  resb 10000
 f3array  :  resb 10000



global _start			; global entry point export for ld

SECTION .text

_start:
start:


	mov rax, 0
.nochmal1:
	mov byte [f1array+rax],0	; alles Array-Elemente zu Null machen.
	mov byte [f2array+rax],0
	mov byte [f3array+rax],0

	inc rax
	cmp rax, 10001
	jne .nochmal1
	mov byte [f1array],1
	mov byte [f2array],1

	mov r15, 5000			; HARDCODED : 5000 fib-Zahlen machen.
							; soviele fib() sollen errechnet werden...
	cmp eax, 0
	jz .done

	dec r15
	jz .done				; wenn fertig, ganz runter, Ende


	
	call .ausgabe_f2	
	call .crlf

.calc_fibo:		
	call .kill_f3
	
	mov r14, 0				; r14 ist Index, wo im Array wir sind.
	mov cl, 0
.alle_ziffern:
	mov rax, 0
	mov rbx, 0
	mov r13, 0
	mov al, byte [f1array+r14]
	add [f3array+r14], al
	mov bl, byte [f2array+r14]
	add [f3array+r14], bl
	mov bl, byte [f3array+r14]
	jo .overflow			; Ergebnis zu groß für Datentyp?
	nop
	nop
	
	inc r14
	cmp r14, 10000
	jne .alle_ziffern

; *****  hier fertig mit rechnen *******



	call .adjust_f3
	
	call .shift_arrays

	cmp r15, 10				; erst ausgeben, wenn es die letzten 10 fibs sind.
	jg	.keine_ausgabe		; ansonsten Ausgabe ueberspringen.
	call .ausgabe_f3		; hier Ausgabe als Text
	call .crlf
	call .crlf
.keine_ausgabe:



 .done:
;	call .crlf
	
	dec r15
	jnz .calc_fibo				; alle Fibos berechnet ?

	mov eax, 1					; Programmende
	mov ebx, 0
	int 80h

.overflow:
	mov eax, 4
	mov ebx, 1
	mov ecx, _overflow_msg
	mov edx, len_overflow_msg
	int 80h

	mov eax, 1
	mov ebx, 1
	int 80h

; *******************************************************************
; *********************** ab hier proceduren ************************
; *******************************************************************


.shift_arrays:
	push rax
	push rbx
	push rcx
	push rdx
	mov rax, 0
.nochmal3:
	mov ch, byte [f2array+rax]
	mov byte [f1array+rax], ch
	
	mov ch, byte [f3array+rax]
	mov byte [f2array+rax], ch
	inc rax
	cmp rax, 10000
	jne .nochmal3
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
	

.crlf:
	push rax
	push rbx
	push rcx
	push rdx
	mov eax, 4					; schreiben
	mov ebx, 1
	mov ecx, _endl
	mov edx, 1
	int 80h
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
	

	
.ausgabe_f2:
	push rax
	push rbx
	push rcx
	push rdx
	mov r12, 10000				; Zur Ausgabe des Arrays r12 als Index	
.noch_ein_array_teil2:
	dec r12
	mov rcx, 0
	mov cl, byte [f2array+r12]
	add ecx, "0"			
	mov byte[ziffer], cl
	mov eax, 4				; fertige "Zahl" ausgeben
	mov ebx, 1
	mov edx, 1				; Länge, hier bei uns immer 1
	mov ecx, ziffer
	int 80h
	cmp r12, 0
	jne .noch_ein_array_teil2
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
	
.ausgabe_f3:
	push rax
	push rbx
	push rcx
	push rdx
	mov r13, 0  			; solange führende Nullen, später dann 1
	mov r12, 10000				; Zur Ausgabe des Arrays r12 als Index	
.noch_ein_array_teil3:
	dec r12
	mov rcx, 0
	mov cl, byte [f3array+r12]
	cmp r13, 0		
	jne .write_it			; wenn schon richtige Ziffern waren, dann hüpfen
	
	cmp cl, 0
	jne .write_it_vor		; wenn ab jetzt richtige Zahlen kommen, dann hüpfen
	push ax
	mov al, [_leerz]
	mov byte[ziffer], al
	pop ax					; führende Null soll Leerzeichen werden
	jmp .ausgabe_leerz
.write_it_vor:
	mov r13,1
.write_it:
	add cl, "0"			
	mov byte[ziffer], cl
.ausgabe_leerz:
	mov eax, 4				; fertige "Zahl" ausgeben
	mov ebx, 1
	mov edx, 1				; Länge, hier bei uns immer 1
	mov ecx, ziffer
	int 80h
	cmp r12, 0
	jne .noch_ein_array_teil3
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret
	
.kill_f3:
	push rax
	mov rax, 0
.nochmal2:
	mov byte [f3array+rax],0
	inc rax
	cmp rax, 10000
	jne .nochmal2
	pop rax
	ret
	
	
.adjust_f3:
	push rax
	push rbx				; Indexzähler
	push rcx				; einzelner Wert
	push rdx
	mov rcx, 0
.nochmal4:
	mov bx, 0
	mov bl, byte [f3array+rcx]
	cmp bl, 10				; größer als 9  ?
	jl .good
	xor ax, ax
	mov ax, bx
	add byte [f3array+rcx+1], 1
	xor rdx, rdx
	mov bx, 10
	div bx
							; Zehner in eax, Einer in rdx
	mov byte [f3array+rcx], dl
.good:
	inc rcx
	cmp rcx, 9999
	jne .nochmal4
	pop rdx
	pop rcx
	pop rbx
	pop rax
	ret

Greetz, Andy

Antworten