Skip to content

Instantly share code, notes, and snippets.

@ksouthworth
Last active March 16, 2016 20:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksouthworth/7590056 to your computer and use it in GitHub Desktop.
Save ksouthworth/7590056 to your computer and use it in GitHub Desktop.
Ruby code to convert an Integer to a Binary Coded Decimal (BCD) array of bytes
# Convert an Integer to a "Packed" Binary Coded Decimal (BCD) formatted array of bytes
# http://en.wikipedia.org/wiki/Binary-coded_decimal
def int_to_bcd_bytes(int)
# BCD format takes each digit of an integer value and encodes it into a nibble (4 bits)
# It maintains the order of the original digits, so 15 would be 00010101
# Since we're dealing with nibbles, we have to zero-pad-left if the number has an odd number of digits
# Decimal digit Binary
# 0 0000
# 1 0001
# 2 0010
# 3 0011
# 4 0100
# 5 0101
# 6 0110
# 7 0111
# 8 1000
# 9 1001
bcd_string = ''
s = int.to_s
s = '0' + s if s.length.odd?
s.chars.each do |digit|
bcd_string += sprintf("%04b", digit) # digit encoded as nibble
end
bcd_bytes = [bcd_string].pack("B*").unpack("C*")
end
@toncid
Copy link

toncid commented Apr 23, 2014

Hello,

The code can be simplified. When converting an integer to string, the string you get is valid BCD. There is no need to go through the string once more before the final pack-unpack. Hence, you need to treat string characters as hex values during packing.

def int_to_bcd_bytes(int)
  bcd_string = int.to_s
  bcd_string.insert(0, '0') if bcd_string.length.odd?
  [bcd_string].pack('H*').unpack('C*')
end

Command line examples:

2.1.1 :117 > result = int_to_bcd_bytes(0); puts "#{result} - #{result.collect { |i| '%02X' % i }}"
[0] - ["00"]
 => nil 
2.1.1 :118 > result = int_to_bcd_bytes(1); puts "#{result} - #{result.collect { |i| '%02X' % i }}"
[1] - ["01"]
 => nil 
2.1.1 :119 > result = int_to_bcd_bytes(10); puts "#{result} - #{result.collect { |i| '%02X' % i }}"
[16] - ["10"]
 => nil 
2.1.1 :120 > result = int_to_bcd_bytes(110); puts "#{result} - #{result.collect { |i| '%02X' % i }}"
[1, 16] - ["01", "10"]
 => nil 
2.1.1 :121 > result = int_to_bcd_bytes(9910); puts "#{result} - #{result.collect { |i| '%02X' % i }}"
[153, 16] - ["99", "10"]
 => nil 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment