Awesome news! JavaScript now Supports BigInts, natively!!

This has landed in node.js and Chrome, and it's documented on MDN, so Firefox support shouldn't be too far behind.

However, it's not documented very well - not even the basic features that already exist or for non-big numbers - like converting Hex to Decimal and back again.

Convert BigInt Hex to Decimal

There are two ways to go about this:

  • Use the BigInt wrapper (which, much like Number, doesn't use new)
  • Use the literal BigInt syntax (postfixing a number with n)

Although you might expect a BigInt.parseInt to complement Number.parseInt(n, 16), that's not the case.

Instead you must use base prefixes (0x for hex).

BigInt('0x102030405060708090a0b0c0d0e0f000').toString(10);
// ↪ "21434780083170533584713300915655864320"

If we break that down a little, we get this:

var hex = '102030405060708090A0B0C0D0E0F000';
var base = 10;
var bn = BigInt('0x' + hex);
// ↪ 21434780083170533584713300915655864320n
bn.toString(base);
// ↪ "21434780083170533584713300915655864320"

You could also use the Hex BigInt literal, but it's (obviously) not as versatile:

0x102030405060708090A0B0C0D0E0F000n.toString(10)
// ↪ "21434780083170533584713300915655864320"

Negative Hex to Dec

BigInts have a sordid past. JavaScript has a sordid past. It's only natural that BigInts in JavaScript have their quirks. Representing negative numbers is one of those tricky parts.

For example, this is obviously an anti-pattern (and wrong):

(-0x102030405060708090A0B0C0D0E0F000n).toString(10)
// ↪ "-21434780083170533584713300915655864320" // WRONG

And this actually gives the wrong type of number:

-0x102030405060708090A0B0C0D0E0F000n.toString(10)
// ↪ -2.1434780083170536e+37 // MORE WRONGER

Traditionally a BigInt will be negative if it's first bit (the "high order bit") is 1 (or 0x80 in hex).

In this scheme, a positive number is designated with a leading 0x00 byte (which is automatically ignored by the BigInt wrapper).

So if we want to handle traditional BigInt numbers we'd do like this:

function hexToBn(hex) {
  if (hex.length % 2) {
    hex = '0' + hex;
  }

  var highbyte = parseInt(hex.slice(0, 2), 16)
  var bn = BigInt('0x' + hex);

  if (0x80 & highbyte) {
    // bn = ~bn; WRONG in JS (would work in other languages)

    // manually perform two's compliment (flip bits, add one)
    // (because JS binary operators are incorrect for negatives)
    bn = BigInt('0b' + bn.toString(2).split('').map(function (i) {
      return '0' === i ? 1 : 0
    }).join('')) + BigInt(1);
    // add the sign character to output string (bytes are unaffected)
    bn = -bn;
  }

  return bn;
}
hexToBn('7F');
// 127n
hexToBn('80');
// -128n
hexToBn('0080');
// 128n
hexToBn('FF');
// -1n

Need the reverse?

See Convert Decimal strings to Hex with JS BigInts.

Looking for more like this?

Check these out too:

Other References


By AJ ONeal

If you loved this and want more like it, sign up!


Did I make your day?
Buy me a coffeeBuy me a coffee  

(you can learn about the bigger picture I'm working towards on my patreon page )



Published

2018-12-11



Buy me a coffeeBuy me a coffee


  73% of Goal Reached


Want more like this?