fast binary to BCD source code

Anyone have C source code to convert 32 bit binary to BCD without using divides. Shift add 3 etc..

Thanks in advance

peejayblack

Reply to
philblack
Loading thread data ...

"philblack":

Something like this? Just rework it for your language, CPU and word-width ;-)

-- Regards, Arie de Muynck

;-------------------------------------------------------------------------- ; BIN24BCD.ASM ; ; Fast 24-bit binary to packed BCD conversion for AVC51_3 ; Small model. ; ; 990822 AdM initial version ;--------------------------------------------------------------------------

global stack_internal defseg c_text,class=CODE seg c_text

_R equ 0 ; register bank 0

;-------------------------------------------------------------------------- ; unsigned long bin24bcd( unsigned long bin) ; ; Convert 24 bits to 8 digits packed bcd. ; ; On entry, ?_bin24bcd+0...3 holds binary value (MSB..LSB). ; The lower 24 bits get stored into R0-1-6. ; On exit, R4-5-6-7 holds packed BCD (MSB...LSB). ; ; Algorithm: ; When the BIN value is leftshifted into the BCD result, each bit that ; would crossover into a higher nibble is really 16, so the BCD result ; is then corrected by adding 6 to the lower nibble. Also, nibbles above 9 ; are corrected by subtracting 10 from the lower nibble and adding 1 ; to the higher one (this is faster if we just add '6', the two's ; complement of 10, to the byte). ; ; Here it is even faster because we add 3 to the lower nibble BEFORE the ; shift, if the result then is > 7 a transfer of the highest bit to the ; next nibble would occur after the shift, so the transfer and the adding ; of 6 would be OK after the shift (6 = 3 9 need not be made. ; ; Algorithm by Alexander Eisen, Electronic Design March 18 1996. ; Converted to Avocet C51 by Arie de Muynck. ; ; Speed: about 1900 cycles (normally: printf("%8lu",..) takes 25700 cycles!) ;--------------------------------------------------------------------------

global _bin24bcd ; setup signatures for linker signat _bin24bcd,4220 ; including call graph info fnsize _bin24bcd,0,4

global ?_bin24bcd ; param _bin assigned to ?_bin24bcd+0..3

_bin24bcd: mov a, ?_bin24bcd ; get MSB jz do24 ; if > 24 bits (0..16777215) mov r2, #99h ; return 99999999 mov r3, #99h mov r4, #99h mov r5, #99h ret do24: mov r0, ?_bin24bcd+1 ; move lower 24 bits to R 0-1-6 (MSB..LSB) mov r1, ?_bin24bcd+2 mov r6, ?_bin24bcd+3

clr cy ; prepare shifting mov r2, #0 ; BCD = 00000000 mov r3, #0 mov r4, #0 mov r5, #0 mov b, #24 ; bits = 24 shloop: ; do xch a, r6 ; shift left BIN into BCD, 1 bit rlc a ; R2345 127 add a, #256-30h ; restore hi: ret

;-------------------------------- eof -------------------------------------

end

Reply to
Arie de Muynck

Here is your homework:

//--------------start of file----------------

extern void bin2bcd(unsigned char *output, unsigned long input);

void bin2bcd(unsigned char *output, unsigned long input) { *output = 0; if (input >= 4000000000) { *output += 0x40; input -= 4000000000; } if (input >= 2000000000) { *output += 0x20; input -= 2000000000; } if (input >= 1000000000) { *output += 0x10; input -= 1000000000; } if (input >= 800000000) { *output += 0x08; input -= 800000000; } if (input >= 400000000) { *output += 0x04; input -= 400000000; } if (input >= 200000000) { *output += 0x02; input -= 200000000; } if (input >= 100000000) { *output += 0x01; input -= 100000000; } output++;

*output = 0; if (input >= 80000000) { *output += 0x80; input -= 80000000; } if (input >= 40000000) { *output += 0x40; input -= 40000000; } if (input >= 20000000) { *output += 0x20; input -= 20000000; } if (input >= 10000000) { *output += 0x10; input -= 10000000; } if (input >= 8000000) { *output += 0x08; input -= 8000000; } if (input >= 4000000) { *output += 0x04; input -= 4000000; } if (input >= 2000000) { *output += 0x02; input -= 2000000; } if (input >= 1000000) { *output += 0x01; input -= 1000000; } output++; *output = 0; if (input >= 800000) { *output += 0x80; input -= 800000; } if (input >= 400000) { *output += 0x40; input -= 400000; } if (input >= 200000) { *output += 0x20; input -= 200000; } if (input >= 100000) { *output += 0x10; input -= 100000; } if (input >= 80000) { *output += 0x08; input -= 80000; } if (input >= 40000) { *output += 0x04; input -= 40000; } if (input >= 20000) { *output += 0x02; input -= 20000; } if (input >= 10000) { *output += 0x01; input -= 10000; } output++; *output = 0; if (input >= 8000) { *output += 0x80; input -= 8000; } if (input >= 4000) { *output += 0x40; input -= 4000; } if (input >= 2000) { *output += 0x20; input -= 2000; } if (input >= 1000) { *output += 0x10; input -= 1000; } if (input >= 800) { *output += 0x08; input -= 800; } if (input >= 400) { *output += 0x04; input -= 400; } if (input >= 200) { *output += 0x02; input -= 200; } if (input >= 100) { *output += 0x01; input -= 100; } output++; *output = 0; if (input >= 80) { *output += 0x80; input -= 80; } if (input >= 40) { *output += 0x40; input -= 40; } if (input >= 20) { *output += 0x20; input -= 20; } if (input >= 10) { *output += 0x10; input -= 10; } *output += (unsigned char)(input & 0x0F); }

unsigned char output[5];

int main(int argc, char* argv[]) {

bin2bcd(output,0xFFFFFFFF); bin2bcd(output,3999999999); bin2bcd(output,0); return 0; }

//--------------end of file----------------

It took me about two hours to think up this method then write and test the code. As you can see there is nothing cleaver or elegant about the code. It's just brute force.

You really should not be so lazy.

Reply to
Keyser Soze

I guess my message did look a bit like a homework request, but really I was looking at why a coworkers code was so slow. I discovered his BCD routine was the culprit with all the divide by 10's. We are displaying a large table of numbers and I know there are better methods to convert.

I was showing him where he ask these types of questions via newsgroups. So this post was for him.

Anyway,

Thanks much for your reply

Phil

Reply to
philblack

Ok, it wasn't homework. :)

The example that Arie de Muynck posted is a very elegant method but it translate poorly to C.

To get a really fast binary to BCD conversion you really need to use assembly language.

The example I posted will generate fast code on a 32 bit CPU, on an 8 bitter it blows chunks.

Reply to
Keyser Soze

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.