22

I am trying without much success to convert a very large hex number to decimal. My problem is that using deciaml = parseInt(hex, 16) gives me errors in the number when I try to convert a hex number above 14 digits.

I have no problem with this in Java, but Javascript does not seem to be accurate above 14 digits of hex.

I have tried "BigNumber" but tis gives me the same erroneous result.

I have trawled the web to the best of my ability and found web sites that will do the conversion but cannot figure out how to do the conversion longhand.

I have tried getting each character in turn and multiplying it by its factor i.e. 123456789abcdef 15 * Math.pow(16, 0) + 14 * Math.pow(16, 1).... etc but I think (being a noob) that my subroutines may not hev been all they should be because I got a completely (and I mean really different!) answer.

If it helps you guys I can post what I have written so far for you to look at but I am hoping someone has simple answer for me.

   <script>
   function Hex2decimal(hex){

   var stringLength = hex.length;
   var characterPosition = stringLength;
   var character;

   var hexChars = new Array();
   hexChars[0] = "0";
   hexChars[1] = "1";
   hexChars[2] = "2";
   hexChars[3] = "3";
   hexChars[4] = "4";
   hexChars[5] = "5";
   hexChars[6] = "6";
   hexChars[7] = "7";
   hexChars[8] = "8";
   hexChars[9] = "9";
   hexChars[10] = "a";
   hexChars[11] = "b";
   hexChars[12] = "c";
   hexChars[13] = "d";
   hexChars[14] = "e";
   hexChars[15] = "f";

   var index = 0;
   var hexChar;
   var result;

   //   document.writeln(hex);

while (characterPosition >= 0)
{
   //   document.writeln(characterPosition);
character = hex.charAt(characterPosition);

    while (index < hexChars.length)
    {
   //       document.writeln(index);
    document.writeln("String Character = " + character);
    hexChar = hexChars[index];
    document.writeln("Hex Character = " + hexChar);

        if (hexChar == character)
        {
        result = hexChar;
        document.writeln(result);
        }

    index++
    }

   //   document.write(character);
characterPosition--;
}

return result;
   }
   </script>

Thank you.

Paul

PAUL WHITE
  • 303
  • 1
  • 3
  • 9

6 Answers6

26

The New 'n' Easy Way

var hex = "7FDDDDDDDDDDDDDDDDDDDDDD";
if (hex.length % 2) { hex = '0' + hex; }

var bn = BigInt('0x' + hex);

var d = bn.toString(10);

BigInts are now available in most browsers (except IE).

Earlier in this answer:

If you need to deal with negative numbers, that requires a bit of work:

Essentially:

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) {
    // You'd think `bn = ~bn;` would work... but it doesn't

    // 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);
    bn = -bn;
  }

  return bn;
}
YakovL
  • 7,557
  • 12
  • 62
  • 102
coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • Is the zero padding actually necessary? Browser console seems to yield expected results for odd scale numbers: `BigInt('0x102') === 258n` – Klesun Jan 28 '21 at 01:37
  • I could consider that a bug - probably residual from some other bug in the language - not a feature. Ultimately it will somehow lead to mistakes and confusion: 1. it's obviously not valid hex. 2. therefore, it's not portable if you tried to copy and paste it as hex to some other environment 3. "clear is better than clever", always. – coolaj86 Aug 22 '22 at 15:46
  • 1
    Not that it mattered, but I don't see how it's obviously not a valid hex. Hex is just digits. [The first](https://www.rapidtables.com/convert/number/hex-to-decimal.html) google result for "hex to decimal" seem to work for the `0x102` input. If I may make a guess, you are possibly assuming that we are considering hex only as representation of bytes, in which case it indeed can't be odd. Oh, yeah, the variable in your code is even named `highbyte`. My comment assumed that for the OP's problem the padding is not necessary, as they are asking about any generic hex, not specifically hex in bytes. – Klesun Aug 22 '22 at 17:35
25

Ok, let's try this:

function h2d(s) {

    function add(x, y) {
        var c = 0, r = [];
        var x = x.split('').map(Number);
        var y = y.split('').map(Number);
        while(x.length || y.length) {
            var s = (x.pop() || 0) + (y.pop() || 0) + c;
            r.unshift(s < 10 ? s : s - 10); 
            c = s < 10 ? 0 : 1;
        }
        if(c) r.unshift(c);
        return r.join('');
    }

    var dec = '0';
    s.split('').forEach(function(chr) {
        var n = parseInt(chr, 16);
        for(var t = 8; t; t >>= 1) {
            dec = add(dec, dec);
            if(n & t) dec = add(dec, '1');
        }
    });
    return dec;
}

Test:

t = 'dfae267ab6e87c62b10b476e0d70b06f8378802d21f34e7'
console.log(h2d(t)) 

prints

342789023478234789127089427304981273408912349586345899239

which is correct (feel free to verify).

georg
  • 211,518
  • 52
  • 313
  • 390
  • This gives the error: Object doesn't support property or method 'forEach' – PAUL WHITE Sep 21 '12 at 17:41
  • You're probably using a very old browser that doesn't support this function. See [here](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach) for how to emulate it. – georg Sep 21 '12 at 17:47
  • I am using frontpage 2003 and ie9. This is probably a limitation of frontpage? – PAUL WHITE Sep 21 '12 at 17:52
  • @PAULWHITE: no idea, but I've rewritten the answer without `forEach`. – georg Sep 21 '12 at 18:09
  • This version gives me a different error: Object doesn't support property or method 'map' – PAUL WHITE Sep 21 '12 at 18:12
  • @thg435: What does `var s = (x.pop() || 0) + (y.pop() || 0) + c;` mean? – Chibueze Opata Jun 06 '13 at 17:49
  • @ChibuezeOpata: "next digit of sum = (last digit of x or 0 if x is empty) + (last digit of y or 0 if y is empty) + carry". Just out of interest, how did you find this post? – georg Jun 06 '13 at 17:54
  • Hmmm, was trying to implement hex to number conversion in C#. See [here](http://stackoverflow.com/q/16965915/612717) Thanks – Chibueze Opata Jun 06 '13 at 18:29
  • @georg just found out this answer, thanks! btw, can I use this function to convert other base number to another base number? for example convert 6 base number to 3 base number (12 become 22, decimal value is 8) – novalagung Apr 17 '15 at 08:53
2

Notice that "0x" + "ff" will be considered as 255, so convert your hex value to a string and add "0x" ahead.

function Hex2decimal(hex)
{
    return ("0x" + hex) / 1;
} 
well7m
  • 21
  • 3
  • 1
    I wonder if what OP considered by "very large hex number" is below the `Number.MAX_SAFE_INTEGER` though. `"0x20000000000000" / 1` yields same result as `"0x20000000000001" / 1` – Klesun Aug 22 '22 at 17:47
1

If you are using the '0x' notation for your Hex String, don't forget to add s = s.slice(2) to remove the '0x' prefix.

Arow
  • 11
  • 1
0

Keep in mind that JavaScript only has a single numeric type (double), and does not provide any separate integer types. So it may not be possible for it to store exact representations of your numbers.

In order to get exact results you need to use a library for arbitrary-precision integers, such as BigInt.js. For example, the code:

var x = str2bigInt("5061756c205768697465",16,1,1);
var s = bigInt2str(x, 10);
$('#output').text(s);

Correctly converts 0x5061756c205768697465 to the expected result of 379587113978081151906917.

Here is a jsfiddle if you would like to experiment with the code listed above.

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • Looking at the code the array entries 10, 11, 12, 13, 14, and 15 should be a, b, c, d, e, and f. – PAUL WHITE Sep 21 '12 at 15:21
  • I scribbled the code a bit too quick as I wanted you guys to see what I was trying to do. – PAUL WHITE Sep 21 '12 at 15:22
  • It would be helpful if you could provide some test cases of numbers that `parseInt` is not converting properly. – Justin Ethier Sep 21 '12 at 15:23
  • OK so what I need to convert is: 5061756c205768697465 to decimal which should be 379587113978081151906917. What I am getting with parseInt is 3.7958711397808114e+23. Even if I reformat the number so it is not scientific the 16th digit onwards is incorrect. – PAUL WHITE Sep 21 '12 at 17:27
  • I ahve been doing some more checking and I am not able to see one on my variables "characther" within a subroutine. Making this a global variable does not help so I am just digging myself deeper into hole now. – PAUL WHITE Sep 21 '12 at 17:28
  • I am going to take a break and come back to this tomorrow. Here is the latest code: – PAUL WHITE Sep 21 '12 at 17:29
  • @PAULWHITE - Please see my latest updates. Because JavaScript does not provide native integer types, you are going to need to use a special library to perform exact conversions. – Justin Ethier Sep 21 '12 at 17:52
0

The BigInt constructor can take a hex string as argument:

/** @param hex = "a83b01cd..." */
function Hex2decimal(hex) {
    return BigInt("0x" + hex).toString(10);
}

Usage:

Hex2decimal("100");

Output:

256

A rip-off from the other answer, but without the meaningless 0 padding =P

Klesun
  • 12,280
  • 5
  • 59
  • 52