Best (eg fastest) way to convert BCD values to Integers #18762
-
|
I have been working with a Real Time Clock that returns it's time values in Binary Coded Decimal format; [eg: (for the uninitiated) when you read the 'seconds' byte, the digits are recorded in the lower four bits (nibble) of the byte, and the tens are similarly held by the upper four bits. so if the clock value is I'm wondering if there is any more efficient way to convert from the BDC value to integer (and v.versa) than the pair of lambda's I came up with: byte_to_bcd = lambda x : 16 * (x // 10) + (x % 10)
bcd_to_byte = lambda x : 10 * (x >> 4 & 0xF) + (x & 0xF)I want to return the clock integer values (eg 6 bytes, YMD:hms, all bcd coded) as fast as possible following an interrupt, so I'm interested in any speedup, especially to the |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 5 replies
-
|
By far the fastest would be to use a translation array (back and forth) |
Beta Was this translation helpful? Give feedback.
-
|
I don't know if it's faster, but if you multiply by a value of the power of 2, then you could use shift operations instead. So, you could shift by 4 instead of multiply by 16 But I don't know what the compiler does and if a shift operation if faster than a multiplication. Two weeks ago, I found this: https://graphics.stanford.edu/~seander/bithacks.html |
Beta Was this translation helpful? Give feedback.
-
|
OOh, thanks everybody for replies. I'm going to do a test with translation (byte)arrays. I'll report the results back here for interests sake if nothing else. |
Beta Was this translation helpful? Give feedback.
-
|
I put together a couple of tests; tables beat logic+arithmetic by 2.5x (or so). MPY: soft reboot
MicroPython v1.27.0 on 2025-12-09; Generic ESP32P4 module with WIFI module of external ESP32C6 with ESP32P4
Type "help()" for more information.
>>> import bcd_to_byte
Converting BCD to Bytes; 10000 conversions
table: 4630 μs
maths: 13772 μs
>>> import byte_to_bcd
Converting Bytes to BCD; 10000 conversions
table: 4723 μs
maths: 12023 μs
>>> Not exactly surprising of course; what did surprise me is how much of a difference it makes by putting the bytearrays in a byte_to_bcd.py from time import ticks_us
# fill a tuple with 0 -> 100 in integers
bytecount = 100 * tuple(range(100))
# bytearray mapping integers to BCD values
byte_bcd_table = const(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 !"#$%&\'()0123456789@ABCDEFGHIPQRSTUVWXY`abcdefghipqrstuvwxy\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99')
def baseline():
start = ticks_us()
for x in bytecount:
_ = x
return ticks_us() - start
def table_pointer():
start = ticks_us()
for x in bytecount:
_ = byte_bcd_table[x]
return ticks_us() - start
def shift_manipulate():
start = ticks_us()
for x in bytecount:
_ = 16 * (x // 10) + (x % 10)
return ticks_us() - start
base = baseline()
print("Converting Bytes to BCD; {} conversions".format(len(bytecount)))
print('table:', table_pointer() - base, 'μs')
print('maths:', shift_manipulate() - base, 'μs')bcd_to_byte.py from time import ticks_us
# fill a tuple with 0 -> 100 in BCD
bcdcount = 100 * [int(str(x),16) for x in range(100)]
# bytearray mapping BCD to integers
bcd_byte_table = const(b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\x00\x00\x00\x00\x00\x00\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x00\x00\x00\x00\x00\x00\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x00\x00\x00\x00\x00\x00\x1e\x1f !"#$%&\'\x00\x00\x00\x00\x00\x00()*+,-./01\x00\x00\x00\x00\x00\x0023456789:;\x00\x00\x00\x00\x00\x00<=>?@ABCDE\x00\x00\x00\x00\x00\x00FGHIJKLMNO\x00\x00\x00\x00\x00\x00PQRSTUVWXY\x00\x00\x00\x00\x00\x00Z[\\]^_`abc')
def baseline():
start = ticks_us()
for x in bcdcount:
_ = x
return ticks_us() - start
def table_pointer():
start = ticks_us()
for x in bcdcount:
_ = bcd_byte_table[x]
return ticks_us() - start
def shift_manipulate():
start = ticks_us()
for x in bcdcount:
_ = 10 * (x >> 4 & 0xF) + (x & 0xF)
return ticks_us() - start
base = baseline()
print("Converting BCD to Bytes; {} conversions".format(len(bcdcount)))
print('table:', table_pointer() - base, 'μs')
print('maths:', shift_manipulate() - base, 'μs') |
Beta Was this translation helpful? Give feedback.
By far the fastest would be to use a translation array (back and forth)
Costs two times 256 bytes.