Why 'C' does not need BCD...

Thomas M. Breuel breuel at harvard.ARPA
Sun Nov 25 15:50:50 AEST 1984


|A Fujitsu Eagle transfers data at about 1.8 megabytes per second.  Many
|mainframe disks are even faster.  If you are storing 6-byte (12-digit) BCD
|and are adding two streams, you are transferring 18 bytes per operation.
|Assuming you double-buffer but have only one controller, this is 100K
|operations per second.  You thus have to convert to binary, add, and
|convert back to BCD in approximately 10 microseconds.

This is irrelevant (sorry). You don't 'have to convert to binary, add,
and convert back to BCD in approximately 10 microseconds', since you
don't store your data in BCD on the disk in the first place if you are
working with binary numbers.

The only time when you have to convert to BCD is when you output data
in human readable form. Since output in human readable form is handled
by slow devices, like line printers, laser printers, or microfilm
printers, it hardly matters how quickly you can perform the
conversion.  (Indeed, for laser printers, most of the work is involved
in generating the bit image). In addition, the amount of data that you
present in human readable form is very likely to be only a tiny
fraction of the amount of data you are doing arithmetic with. (This is
due to the limited performance of human beings).

Apart from the above points, there is most likely an operating system
in between your nice, fast disk drives and your ('C') program. Indeed,
this operating system is likely to be UN*X. Since (if I recall
correctly) the calling sequence on the VAX takes more than 10us, and
since UN*X loves to call many functions and to do a lot of copying, it
again hardly matters whether your arithmetic takes 10us or 20us or
100us.

Even if you, as I once did on an IBM360, program your machine in
assembly language and access the disk drives directly (i.e. with
minimum overhead), you would still have to do seeks ('double buffering'
doesn't really help you), either every now-and-then (if you are lucky
enough to have three disk drives), or for every operation (if you are
not lucky enough).

The slowness of disk I/O is not related to transfer rates (1.8 Mbyte/s
is almost as fast as dynamic ram chips), but to seek times and
scheduling problems (DMA, processor interrupt service, ...).

|                                               But I have never seen an
|algorithm for converting binary to decimal without doing divisions.

If you keep on reading, you'll find an algorithm that converts binary
to BCD without division.

|And it's actually worse than that, because a mainframe that powerful
|typically has several controllers so that the full 1.8 megabyte output data
|rate could be maintained if the CPU could keep up with it.

As mentioned above, disk transfer rate is not the limiting factor.

|[somebody else mentioned something like:] 5 digit signed BCD takes
|3 bytes, whereas for a binary representation you have to go from
|16 to 32 bits.

You can do your arithmetic with 32 bits and store data as 24 bits
on disk (that's what UN*X used to do on PDP-11's).

To summarise: binary arithmetic is faster than BCD arithmetic,
binary->ASCII is slower than BCD->ASCII. Binary numbers are equally or
more compact than BCD numbers. Binary numbers are equally readable,
even for accountants, given that your debugger does not only support hex
dumps (BTW, have you ever tried to read BCD in an octal dump?).

WRT 'C', all of this is irrelevant. If you want to use BCD in 'C', write
your own assembly language subroutines, the same way that you write
your own string routines. You then even have the choice between packed
and unpacked BCD, so that your BCD routines can even *be* your string
routines :-). 'C' as the language to write UN*X and UN*X utilities in,
surely does not need BCD.

Sorry for this somewhat lengthy response. I hope it will by {my,the}
last one on the subject.

						Thomas.
						(breuel at harvard)

PS: if you are worried about efficiency in your BCD package, why don't
you just write an sed-script, which replaces all 'calls' to BCD
routines by in-line assembly language. That's how the kernel handles
'bcopy' and friends on the VAX.

PPS: the same sed-script can even be applied to PDP-11 'C' compiler
output without harm, as the 2.9BSD distribution clearly demonstrates --
PDP-11 code does not contain 'calls'...

-----------------------------------------------------------------------

; As promised: routine to convert binary to BCD without division.

; You can write this routine for any machine with BCD arithmetic.
; I can write it only for the 6502, 68000, 8085, IBM360 (:-)), or
; VAX. Of those, I think it looks neatest on the 6502.

; There are likely to be some misspelled mnemonics in here --
; I haven't written 6502 assembly language in 2 years.

; Entry: binary number between 0 and 99 in accumulator
; Exit: BCD number in accumulator (unpack to get ASCII)

	php		; save previous processor mode
	sed		; enable bcd arithmetic
	ldx #8		; #bits to convert
	ldy #0		; clear result
	sty r		
loop:
	asl a		; test msb
	tay		; save binary number
	php		; save result of msb test
	lda r		; multiply bcd by 2
	add r		
	plp		; add one if msb was set
	bcc skip	
	add #1		
skip:
	sta r		; update bcd result
	tya		; restore binary number
	dex		
	bra loop	
	lda r		; return result in accumulator
	plp		; restore processor status
	rts		



More information about the Comp.lang.c mailing list