Search code examples
javascriptmathbigintegerbignum

Convert base 10 and base 255 integer strings in JavaScript?


Does anyone know a way to convert base 10 and base 255 strings in JavaScript exceeding the Number.MAX_SAFE_INTEGER value without using a big number library?

For something like:

var base10 = '23456786543234567876543234567876543267';
var base255 = base10ToBase255(base10);

To base-255 or from base-255 as:

var base255 = new Uint8Array(20);
for (var i = 0; i < 20; i++) base255[i] = 254 - i;
var base10 = base255ToBase10(base255);

Solution

  • EDITED: changed to allow for other bases (<=256) It always boils down to using a big integer, sorry. But you do not need much, it's just about 100 lines of code for what you want (string to base 256 and back).

    "use strict";
    var COMMON_BASE = 255; // must be 256 at most!
    function copyA(a){
        var ret = new Uint8Array(a.length);
        for(var i = 0;i<a.length;i++){
            ret[i] = a[i];
        }
        return ret;
    }
    
    function isZero(a){
        for(var i = 0;i<a.length;i++){
            if(a[i] !== 0)
                return false;
        }
        return true;
    }
    
    function clampA(a){
        var alen = a.length;
        var i=0;
        while(a[alen - 1] === 0)alen--;
        var ret = new Uint8Array(alen);
        for(var i = 0;i<alen;i++){
            ret[i] = a[i];
        }
        return ret;
    }
    
    
    function addD(a,d) {
        var tlen = a.length;
        var carry = 0;
        var ret = new Uint8Array(tlen +1);
        if(d === 0)
            return copyA(a);
        var i = 0;
        var temp = carry;
        temp += a[i] + d;
        carry = Math.floor(temp / COMMON_BASE);
        ret[i] = temp % COMMON_BASE;
        for (i = 1; i < tlen; i++) {
            temp = carry;
            temp += a[i];
            carry = Math.floor(temp / COMMON_BASE);
            ret[i] = temp % COMMON_BASE;
        }
        if (carry) {
            ret[i] = carry;
        }
    
        ret = clampA(ret);
        return ret;
    };
    
    function mulD(a,d){
        var tlen = a.length;
        var carry = 0;
        var ret = new Uint8Array(tlen + 1);
        var k = 0;
        var tmp;
        if(isZero(a))
            return copyA(a);
        if(d === 0)
            return new Uint8Array(tlen);
        for (; k < tlen; k++) {
            tmp = a[k] * d + carry;
            ret[k] = tmp % COMMON_BASE;
            carry = Math.floor(tmp / COMMON_BASE);
        }
        if (carry) {
            ret[k] = carry;
        }
        ret = clampA(ret);
        return ret;
    }
    
    function divRem(a,d){
          var divrem = function(u, m, v, q, B) {
            var k = 0,
                t;
            for (var j = m - 1; j >= 0; j--) {
                k = (k * COMMON_BASE) ;
                k += u[j];
                if (k >= v) {
                    t = Math.floor(k / v);
                    k -= t * v;
                } else {
                    t = 0;
                }
                q[j] = t;
            }
            return k;
        };
        var Q = new Uint8Array(a.length);
        var R = divrem(a,a.length, d, Q, 8);
        Q = clampA(Q);
        return [Q,R];
    }
    
    // Assuming 's' being a string with decimal digits
    function base10ToBase256(s){
      var blen = 0;
      // checks&balances omitted
      var out = new Uint8Array(1);
      for(var i=0;i<s.length;i++){
        out = mulD(out,10);
        out = addD(out,parseInt(s[i],10) );
      }
      return out;
    }
    // Assuming b being a Uint8Array
    function base256ToBase10(a){
      var s = "";
      var t = copyA(a);
      var qr = [];
      var i = a.length;
      while(!isZero(t)){
        qr = divRem(t,10);
        s = s + qr[1].toString(10);
        t = qr[0];
      }
      return s.split("").reverse().join("");
    }
    
    var str = "8716418673416734167345634096788356249857";
    //base10ToBase256(str).join(",");
    base256ToBase10(base10ToBase256(str));
    
    
    
    var str = "8716418673416734167345634096788356249857";
    console.log(base10ToBase256(str).join(","));
    console.log(base256ToBase10(base10ToBase256(str)));
    

    Here the LSB is at position zero. It's a rough hack (way too much copies etc.) but it'll do it.