Type in an arbitrarily long hex or dec string:


So what's going on here? JavaScript uses a 64-bit floating point representation to store all numbers, even integers. This means that integers larger than 2^53 cannot be represented precisely in JS.

This becomes a problem if you need to work with 64-bit numbers, say to convert them between hexadecimal (base 16) and decimal (base 10). This is not an uncommon need, since many hash functions output 64-bit integers.

This page converts between arbitrarily large decimal and hex numbers without loss of precision. It does this by working with strings and arrays of digits, rather than native JS numbers. This means it's slower than built-in functions like parseInt, but you'd rather be accurate than fast, right?

The underlying algorithm is fairly simple. Say we're converting hex to decimal. Then we represent numbers as arrays of decimal digits, starting with the least-significant. So:

  • 1 = [1]
  • 10 = [0, 1]
  • 1024 = [4, 2, 0, 1]

We can implement a general add(x, y) function for these arrays of digits. This turns out to be all we need to do the base conversion.

Since 2x = x + x, an add function lets you compute all the powers of two:

  • 2^0 = [1]
  • 2^1 = add(2^0, 2^0) = add([1], [1]) = [2]
  • 2^2 = add(2^1, 2^1) = add([2], [2]) = [4]
  • 2^3 = add(2^2, 2^2) = add([4], [4]) = [8]
  • 2^4 = add(2^3, 2^3) = add([8], [8]) = [6, 1]
  • 2^5 = add(2^4, 2^4) = add([6, 1], [6, 1]) = [2, 3]

Now, given a hex string, we can easily break it down into binary digits. Each hex digit corresponds to four binary digits. These binary digits tell us how to form the number by adding together powers of two. We already have an add function and the powers of two, so we're all set!

For example, to convert 0x123 from hex to decimal, we:

  1. Convert 0x123 → (binary) 0001 0010 0011
  2. Compute powers of two:
     2^0 = [1]
     2^1 = [2]
     2^5 = [2, 3]
     2^8 = [6, 5, 2]
  3. Add them up: add([1], add([2], add([2, 3], [6, 5, 2]))) = [1, 9, 2]
  4. Convert back to a string: [1, 9, 2] → "291".

If you'd like to use this or see how this works, view the source. It's fairly short (~65 lines of real code) and well-commented. It can be copy/pasted into your own project.

This code may be used under the Apache 2 license.

Please leave comments! It's what makes writing worthwhile.

comments powered by Disqus