Search code examples
pythonbcd

Convert amount (int) to BCD


I need to convert an Int left padded 6 bytes (amount) to a BCD in Python.

int = 145
expect = "\x00\x00\x00\x00\x01\x45"

The closest I come is with this code (but it needs to loop in byte pair):

def TO_BCD(value):
    return chr((((value / 10) << 4) & 0xF0) + ((value % 10) & 0x0F))

int = 145
TO_BCD(int) # => "\x00\x00\x00\x00\x01\x45" (expected)


Solution

  • This seems fairly simple, and gets the answer you were looking for. Just isolate each pair of digits and convert to ASCII.

    If I were doing this in high volume then I'd probably build a table (perhaps in numpy) of all the possible 100 values per byte and index it with each pair of digits in the input.

    m = 145
    print(''.join(f"\\x{m // 10**i % 10}{m // 10**(i-1) % 10}" for i in range(11, -1, -2)))
    

    Output, although it's just a string, not any internal BCD representation

    \x00\x00\x00\x00\x01\x45
    

    Along the same lines, you can pack the BCD into a byte string. When printed, Python will interpret BCD 45 as a capital E

    import struct
    m = 145
    
    packed = struct.pack('6B', *[(m // 10**i % 10 << 4) + (m // 10**(i-1) % 10) for i in range(11, -1, -2)])
    print(packed)
    print(''.join(f"\\{p:02x}" for p in packed))
    

    Output

    b'\x00\x00\x00\x00\x01E'
    \00\00\00\00\01\45