Last active
September 9, 2022 09:36
-
-
Save mneumann/a34c1823f89cfd18cd49eeae89d46ccf to your computer and use it in GitHub Desktop.
Convert number into decimal representation via packed BCD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Convert number into decimal representation intermediate packed BCD. | |
# Uses two 64-bit integers | |
def assert_eq(a, b) | |
raise "#{a} != #{b}" unless a == b | |
end | |
def number_to_packed_bcd_int(n) | |
raise if n > (10**32) - 1 | |
# Use two u64 | |
bcd_high, bcd_low = 0, 0 | |
ndigits = 0 | |
loop do | |
ndigits += 1 | |
digit = n % 10 | |
n /= 10 | |
bcd_high = (bcd_high << 4) & 0xFFFFFFFF_FFFFFFFF | |
bcd_high = bcd_high | (bcd_low >> 60) & 0xF | |
bcd_low = (bcd_low << 4) & 0xFFFFFFFF_FFFFFFFF | |
bcd_low = bcd_low | digit | |
break if n == 0 | |
end | |
[ndigits, bcd_high, bcd_low] | |
end | |
def packed_bcd_int_to_string(ndigits, bcd_high, bcd_low) | |
raise if ndigits == 0 | |
s = String.new("", capacity: ndigits) | |
ndigits.times do | |
digit = bcd_low & 0xF | |
s << ('0'.ord + digit).chr | |
bcd_low = (bcd_low >> 4) | (bcd_high & 0xF) << 60 | |
bcd_high = bcd_high >> 4 | |
end | |
s | |
end | |
def to_decimal_s(n) | |
packed_bcd_int_to_string(*number_to_packed_bcd_int(n)) | |
end | |
assert_eq(number_to_packed_bcd_int(0), [1, 0, 0]) | |
assert_eq(number_to_packed_bcd_int(9), [1, 0, 9]) | |
assert_eq(number_to_packed_bcd_int(10), [2, 0, 1]) | |
assert_eq(number_to_packed_bcd_int(56), [2, 0, 5 | (6 << 4)]) | |
assert_eq(number_to_packed_bcd_int(100), [3, 0, 1]) | |
assert_eq(number_to_packed_bcd_int(12345), [5, 0, 1 | (2 << 4) | (3 << 8) | (4 << 12) | (5 << 16)]) | |
assert_eq(packed_bcd_int_to_string(2, 0, 5 | (6 << 4)), "56") | |
assert_eq(to_decimal_s(12345), "12345") | |
1000.times do | |
n = rand(1_000_000_000_000) | |
assert_eq(to_decimal_s(n), n.to_s(10)) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment