Dezimalausgaben

Meist werden in Programmen Zahlen dezimal ein- und ausgegeben. Ein grundlegender Artikel mit verschieden Zahlenbasen findet sich hier. Während die Eingabe einer Dezimalzahl und ihre Wandlung in eine Binärzahl relativ einfach ist — siehe dazu den Artikel — gibt es bei der dezimalen Ausgabe einer Binärzahl mehrere Möglichkeiten, von denen ich einige hier zusammengestellt habe.
Beschreibung der Sammlung:
Allen Routinen gemeinsam ist:
  1. Im Register HL steht der Binärwert
  2. Register werden nicht gerettet
  3. Die externe Routine APUT, die die aktuelle Ziffer speichert.
    Z.B.:
    APUT:
    	push	hl		; Register retten
    	ld	hl,(DIGBUF)	; Pufferadresse laden
    	ld	(hl),a		; Ziffer abspeichern
    	inc	hl
    	ld	(hl),0		; Ende anzeigen
    	ld	(DIGBUF),hl	; Adresse speichern
    	pop	hl		; Register holen
    	ret
    
    Vor Aufruf der Wandlung muss DIGBUF gesetzt werden. Natürlich kann APUT auch eine Routine zur Ausgabe sein.
MethodeCodelänge in Bytes
Rekursion25
Tabelle (1)59
Tabelle (2)48
Negative Konstanten76
Positive Konstanten47
Über BCD89

;
; Rekursive Wandlung
;
Methode1:
	ld	bc,-10		; Konstante laden
Numb:
	ld	de,-1
.Numb:
	add	hl,bc		; 10s abziehen
	inc	de		; Anzahl zaehlen
	jr	c,.Numb		; Weiter bis Rest negativ
	push	hl		; Rest - 10 sichern
	ex	de,hl
	ld	a,h		; Anzahl 10 testen
	or	l		; Test ob Quotient Null ist
	call	nz,Numb		; Wenn nicht, rekursiv aufrufen
	pop	hl		; Rest - 10 laden
	ld	a,l
	add	a,'0'+10	; Ziffer druckbar machen
	call	APUT		; Ziffer ablegen
	ret

;
; Wandlung ueber Tabelle
;
Methode2:
	ld	ix,tentbl	; Start der Tabelle laden
	ld	c,1		; Set zero flag
dotpos:
	ld	e,(ix)		; Get divisor
	inc	ix
	ld	d,(ix)
	inc	ix
	ld	b,-1		; Clear digit
dotdiv:
	inc	b		; Count digits
	or	a
	sbc	hl,de		; Divide
	jr	nc,dotdiv
	add	hl,de		; Make > 0
	xor	a
	or	b		; Test zero digit
	jr	nz,dotstr
	or	c		; Clear leading zero
	jr	nz,dotbyp
dotstr:
	ld	c,0		; Clear zero flag
	or	'0'		; Make ASCII
	call	APUT		; Put anywhere
dotbyp:
	ld	a,e		; Test end of table
	cp	10
	jr	nz,dotpos
	ld	a,l
	or	'0'
	call	APUT		; Put anywhere
	ret
;
tentbl:
	dw	10000
	dw	 1000
	dw	  100
	dw	   10

;
; Wandlung ueber Tabelle
;
Methode3:
	ld	ix,tentbl	; Start der Tabelle laden
	ld	bc,256*5+'0'	; Set length
dotpos:
	ld	e,(ix+0)	; Get divisor
	ld	d,(ix+1)
	ld	a,'0'-1		; Clear digit
	or	a
dotdiv:
	inc	a		; Count digits
	sbc	hl,de		; Divide
	jr	nc,dotdiv
	add	hl,de		; Make > 0
	cp	c		; Test zero digit
	jr	nz,dotstr
	ld	a,' '
	inc	c		; Clear leading zero
dotstr:
	call	APUT		; Put anywhere
	dec	c
	inc	ix
	inc	ix
	djnz	dotpos
	ret
;
tentbl:
	dw	10000
	dw	1000
	dw	100
	dw	10
	db	1

;
; Division mit negativen Konstanten
;
Methode4:
	ld	d,0		; Set no leading zero
	ld	e,5		; Set max number of digits
	call	divpow10	; Get digits
	dw	-10000
	call	divpow10
	dw	-1000
	call	divpow10
	dw	-100
	call	divpow10
	dw	-10
	ld	d,'0'		; Allow zeroes now
	call	divpow10
	dw	-1
	inc	e
trail:
	dec	e		; Test all digits printed
	ret	z		; Yeap
	ld	a,' '
	call	APUT		; Put trailing blanks anywhere
	jr	trail
;
; Print quotient as decimal number [HL DIV <SP>]
;
divpow10:
	ex	(sp),hl
	ld	c,(hl)		; Fetch divisor
	inc	hl
	ld	b,(hl)
	inc	hl
	ex	(sp),hl
	ld	a,'0'		; Init digit
divloop:
	push	hl		; Save value
	add	hl,bc		; Divide
	jr	nc,divend	; Get result
	inc	a		; Advance quotient
	inc	sp		; Delete remainder
	inc	sp
	jr	divloop
divend:
	pop	hl		; Get back remainder
	cp	'0'		; Test possible leading zero
	jr	nz,not0		; Nope
	ld	a,d		; Get state of leading zero
	jr	tst0		; Test leading zero allowed
not0:
	ld	d,'0'		; Set no leading zero
tst0:
	cp	0		; Test leading zero allowed
	ret	z		; Nope
	call	APUT		; Put anywhere
	dec	e		; Count down remaining length
	ret

;
; Division mit positiven Konstanten
;
Methode5:
	ld	b,0		; Init flag
	ld	de,10000
	call	divpow10	; Start with 10000s
	ld	de,1000
	call	divpow10	; Then 1000s
	ld	de,100
	call	divpow10	; Then 100s
	ld	e,10
	call	divpow10	; Then 10s
	ld	a,l		; Get remainder
	jr	lastdig
divpow10:
	xor	a		; Clear quotient
divloop:
	inc	a		; Advance quotient
	sbc	hl,de		; Divide
	jr	nc,divloop	; Still positive
	add	hl,de		; Fix for last number
	inc	b		; Access flag
	dec	a		; Test zero digit
	jr	nz,lastdig	; Nope, so store result
	dec	b		; Test flag
	ret	z		; No leading zeroes
lastdig:
	add	a,'0'		; Make ASCII
	call	APUT		; Put anywhere
	ret

;
; Der Wert des HL-Register wird dezimal ausgegeben, und zwar
; rechtsbuendig fuehrende Nullen werden unterdrueckt
;
Methode6:
	ex	de,hl
	ld	a,0		
	ld	b,3
	ld	hl,DecBuff
HexIni:
	ld	(hl),a		; Bytes loeschen
	inc	hl
	djnz	HexIni
	ld	b,16		; Bitlaenge setzen
HexDiv:
	ex	de,hl
	add	hl,hl		; Hoechstes Bit holen
	ex	de,hl
	push	bc
	ld	b,3
	ld	hl,DecBuff
HexBCD:
	ld	a,(hl)
	adc	a,(hl)		; Hoechstes Bit addieren
	daa			; Zahl als BCD
	ld	(hl),a
	inc	hl
	djnz	HexBCD
	pop	bc
	djnz	HexDiv
	ld	b,3		; Anzahl Bytes laden
	ld	c,3*2		; Anzahl Zeichen laden
	ld	hl,DecBuff+2	; Zeiger auf hoechste BCD Zahl
nbyte:
	ld	a,(hl)		; BCD laden
	call	ByteOut		; Ausgeben
	dec	hl
	djnz	nbyte
	ret
;
; BCD Byte im Accu ausgeben
;
ByteOut:
	push	af
	srl	a		; Obere Bits holen
	srl	a
	srl	a
	srl	a
	call	DecOut		; Ausgaben
	pop	af
DecOut:
	and	00001111b	; Bits maskieren
	or	'0'
	dec	c		; Test ob letzte Stelle
	jr	z,TTYOut	; Dann kein Test ob Null
	bit	7,c		; Test ob fuehrende Null
	jr	nz,TTYOut	; Nein
	cp	'0'		; Ist dies eine Null?
	jr	z,Zero		; Falls ja, dann ignorieren
	set	7,c		; Markierung keine Null
Zero:
	jr	nz,TTYOut	; Ausgabe
	ld	a,' '		; Fuehrende Null als Leerzeichen
;
; Zeichen auf Konsole ausgeben
;
TTYOut:
	call	APUT		; Put anywhere
	ret
;
DecBuff:
	ds	3

Werner Cirsovius Zusammengestellt seit Januar 2008