nedoPC.org

Electronics hobbyists community established in 2002
Atom Feed | View unanswered posts | View active topics It is currently 14 May 2024 06:38



Reply to topic  [ 2 posts ] 
Javascript implementation of balanced ternary 
Author Message
Junior

Joined: 02 May 2024 05:02
Posts: 1
Reply with quote
Code:
TernaryI32 = (function () {
   "use strict";

   let MAX_VALUE =  926510094425920;
   let MIN_VALUE = -926510094425920;

   function ctor(value) {
      let result = new.target ? this : Object.create(ctor.prototype);
      if (value instanceof ctor) {
         result.pos = value.pos;
         result.neg = value.neg;
      } else {
         let pos = 0, neg = 0, rem;
         value = Math.trunc(value);
         if (!Number.isSafeInteger(value)) value = 0;
         for (let i = 1; i && value; i <<= 1) {
            rem = value % 3;
            rem = (rem % 2 * 3 - rem) / 2;
            if (rem > 0) pos += i;
            if (rem < 0) neg += i;
            value = (value - rem) / 3;
         }
         result.pos = pos;
         result.neg = neg;
      }
      return result;
   };

   function abs(a) {
      return sign(a) < 0 ? neg(a) : ctor(a);
   };

   function add(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      let pos_XOR = pos_A ^ pos_B;
      let neg_XOR = neg_A ^ neg_B;
      let t = pos_XOR & neg_XOR;
      pos_XOR ^= t;
      neg_XOR ^= t;
      let pos_AND = pos_A & pos_B;
      let neg_AND = neg_A & neg_B;
      let pos_P = pos_XOR | pos_AND;
      let neg_P = neg_XOR | neg_AND;
      let pos_G = pos_XOR | neg_AND;
      let neg_G = neg_XOR | pos_AND;
      let pos_SUM = pos_G;
      let neg_SUM = neg_G;
      for (let step = 1; step <= 16; step += step) {
         let pos_Pr = pos_P << step;
         let neg_Pr = neg_P << step;
         let pos_Gr = pos_G << step;
         let neg_Gr = neg_G << step;
         t = pos_Gr | neg_Gr;
         pos_P &= pos_Pr | ~(pos_G | (neg_G & neg_Pr & ~t));
         neg_P &= neg_Pr | ~(neg_G | (pos_G & pos_Pr & ~t));
         t = (pos_G & pos_Pr) | (neg_G & neg_Pr);
         pos_G = t & pos_Gr;
         neg_G = t & neg_Gr;
      }
      pos_P <<= 1;
      neg_P <<= 1;
      pos_XOR = pos_P ^ pos_SUM;
      pos_XOR = neg_P ^ neg_SUM;
      t = pos_XOR & neg_XOR;
      pos_AND = pos_P & pos_SUM;
      neg_AND = neg_P & neg_SUM;
      let result = Object.create(ctor.prototype);
      result.pos = neg_AND | (pos_XOR ^ t);
      result.neg = pos_AND | (neg_XOR ^ t);
      return result;
   };

   function addcarry(a, b, cin) {
      let t = addext(a, b);
      a = t[0];
      let cout = t[1];
      if (cin > 0) {
         b = inc(a);
         if (a.pos === -1) cout = Math.min(cout, 0) + 1;
      } else if (cin < 0) {
         b = dec(a);
         if (a.neg === -1) cout = Math.max(cout, 0) - 1;
      } else {
         b = a;
      }
      return [b, cout];
   };

   function addext(a, b) {
      let sum = add(a, b);
      let carry = sign(a);
      if (carry !== sign(b) || carry === sign(sum)) carry = 0;
      return [sum, carry];
   };

   function cast(value) {
      return value instanceof ctor ? value : ctor(value);
   };

   function cldiv(a, b) {
      return cldiv_i(a, b)[0];
   };

   function cldiv_i(a, b) {
      let sign_B = sign(b);
      if (sign_B < 0) {
         a = neg(a); b = neg(b);
      } else if (!sign_B) {
         return null;
      }
      let exp_A = 31 - Math.clz32(a.pos | a.neg);
      let exp_B = 31 - Math.clz32(b.pos | b.neg);
      let pos_Q = 0;
      let neg_Q = 0;
      while (exp_A >= exp_B) {
         let i = exp_A - exp_B;
         if ((a.pos >> exp_A) & 1) {
            a = tritsub(a, shift(b, i));
            pos_Q |= 1 << i;
         } else if ((a.neg >> exp_A) & 1) {
            a = tritadd(a, shift(b, i));
            neg_Q |= 1 << i;
         }
         exp_A--;
      }
      if (sign_B < 0) {
         a = neg(a);
      }
      let q = Object.create(ctor.prototype);
      q.pos = pos_Q;
      q.neg = neg_Q;
      return [q, a];
   };

   function clmul(a, b) {
      if (((a.pos | a.neg) >>> 0) < ((b.pos | b.neg) >>> 0)) {
         let t = a; a = b; b = t;
      }
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      let both_B = pos_B | neg_B;
      let result = ctor(0);
      for (let i = 0; both_B; i++) {
         let j = 1 << i;
         if (both_B & j) {
            both_B ^= j;
            result = ((pos_B & j) ? tritadd : tritsub)(result, shift(a, i));
         }
      }
      return result;
   };

   function clmulinv(a) {
      let sign = a.neg & 1;
      if (sign) {
         a = neg(a);
      } else if (!(a.pos & 1)) {
         return null;
      }
      let b = ctor(1);
      let pos_R = 0;
      let neg_R = 0;
      for (let i = 0; i < 32; i++) {
         if (b.pos & 1) {
            b = tritsub(b, a);
            pos_R |= 1 << i;
         } else if (b.neg & 1) {
            b = tritadd(b, a);
            neg_R |= 1 << i;
         }
         b = shift(b, -1);
      }
      if (sign) {
         let t = pos_R; pos_R = neg_R; neg_R = t;
      }
      let result = Object.create(ctor.prototype);
      result.pos = pos_R;
      result.neg = neg_R;
      return result;
   };

   function clpow(a, n) {
      if (!(n >= 0 && n <= Number.MAX_SAFE_INTEGER)) {
         return null;
      }
      let s = (a.pos & 1) - (a.neg & 1);
      if (!s && n > 31) return ctor(0);
      let b = [a, clmul(a, a)];
      let r = n % 3;
      let c = r ? b[r - 1] : ctor(1);
      for (let step = 3; n = (n - r) / 3, n > 0 && step < 32; step *= 3) {
         r = n % 3;
         if (r) {
            let d = b[r - 1];
            let pos_D = d.pos | 0;
            let neg_D = d.neg | 0;
            let both_D = pos_D | neg_D;
            let n = 32 / step;
            a = ctor(0);
            for (let i = 0; i < n && both_D; i++) {
               let j = 1 << i;
               if (both_D & j) {
                  both_D ^= j;
                  a = (pos_D & j ? tritadd : tritsub)(a, shift(c, i * step));
               }
            }
            c = a;
         }
      }
      if (s < 1 && n % 2) c = neg(c);
      return c;
   };

   function clrem(a, b) {
      return cldiv_i(a, b)[1];
   };

   function clz32(a) {
      return Math.clz32(a.pos | a.neg);
   };

   function cmp(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      a = ((pos_A & ~pos_B) | (neg_B & ~neg_A)) >>> 0;
      b = ((pos_B & ~pos_A) | (neg_A & ~neg_B)) >>> 0;
      return Math.sign(a - b);
   };

   function ctz32(a) {
      a = a.pos | a.neg;
      return a ? 31 - Math.clz32(a & -a) : 32;
   };

   function dec(a) {
      return neg(inc(neg(a)));
   };

   function div(a, b) {
      let t = divrem_i(a, b);
      return t && ctor(t[0]);
   };

   function divrem_i(a, b) {
      b = valueOf(b);
      if (!b) return null;
      a = valueOf(a);
      let r = a % b;
      return [(a - r) / b, r];
   };

   function inc(a) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let b = pos_A + 1;
      let c = b & -b;
      let result = Object.create(ctor.prototype);
      result.pos = b & ~(neg_A & c);
      result.neg = (neg_A & ~c) | (c - 1);
      return result;
   };

   function max(a, b) {
      return ctor(cmp(a, b) < 0 ? a : b);
   };

   function min(a, b) {
      return ctor(cmp(a, b) > 0 ? a : b);
   };

   function mul(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      let hi_A = valueOf({pos: pos_A >>> 16, neg: neg_A >>> 16});
      let lo_A = valueOf({pos: pos_A & 0xFFFF, neg: neg_A & 0xFFFF});
      let hi_B = valueOf({pos: pos_B >>> 16, neg: neg_B >>> 16});
      let lo_B = valueOf({pos: pos_B & 0xFFFF, neg: neg_B & 0xFFFF});
      return ctor((hi_A * lo_B + hi_B * lo_A) % 43046721 * 43046721 + lo_A * lo_B);
   };

   function mulext(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      let hi_A = valueOf({pos: pos_A >>> 16, neg: neg_A >>> 16});
      let lo_A = valueOf({pos: pos_A & 0xFFFF, neg: neg_A & 0xFFFF});
      let hi_B = valueOf({pos: pos_B >>> 16, neg: neg_B >>> 16});
      let lo_B = valueOf({pos: pos_B & 0xFFFF, neg: neg_B & 0xFFFF});
      let hi_C = hi_A * hi_B;
      let mi_C = hi_A * lo_B + hi_B * lo_A;
      let lo_C = lo_A * lo_B;
      let r = mi_C % 43046721;
      lo_C += r * 43046721;
      hi_C += (mi_C - r) / 43046721;
      if (lo_C > MAX_VALUE) {
         lo_C -= 1853020188851841;
         hi_C ++;
      } else if (lo_C < MIN_VALUE) {
         lo_C += 1853020188851841;
         hi_C --;
      }
      return [ctor(lo_C), ctor(hi_C)];
   };

   function mulinv(a) {
      a = valueOf(a);
      if (!(a % 3)) return null;
      let x = a % 43046721;
      let y = (1 - x * x) % 43046721;
      while (y) {
         x = x * (1 + y) % 43046721;
         y = y * y % 43046721;
      }
      let lo = a % 43046721;
      let hi = (a - lo) / 43046721;
      return ctor(x + ((1 - lo * x) / 43046721 - hi * x % 43046721) * x % 43046721 * 43046721);
   }

   function nabs(a) {
      return neg(abs(a));
   };

   function nadd(a, b) {
      return neg(add(a, b));
   };

   function neg(a) {
      let result = Object.create(ctor.prototype);
      result.pos = a.neg;
      result.neg = a.pos;
      return result;
   };

   function nmax(a, b) {
      return neg(max(a, b));
   };

   function nmin(a, b) {
      return neg(min(a, b));
   };

   function nmul(a, b) {
      return neg(mul(a, b));
   };

   function parity(a) {
      a = a.neg | a.pos;
      a ^= a >> 16;
      a ^= a >> 8;
      a ^= a >> 4;
      return (0x6996 >> (a & 15)) & 1;
   };

   function pow(a, n) {
      if (!(n >= 0 && n <= Number.MAX_SAFE_INTEGER)) {
         return null;
      }
      let result = ctor(1);
      while (n >= 1) {
         if (n % 2 >= 1) {
            result = mul(result, a);
         }
         a = mul(a, a);
         n /= 2;
      }
      return result;
   };

   function rem(a, b) {
      let t = divrem_i(a, b);
      return t && ctor(t[1]);
   };

   function shift(a, n) {
      let pos, neg;
      if (n < -31 || n > 31) {
         pos = neg = 0;
      } else if (n < 0) {
         pos = a.pos >>> (-n);
         neg = a.neg >>> (-n);
      } else {
         pos = a.pos << n;
         neg = a.neg << n;
      }
      let result = Object.create(ctor.prototype);
      result.pos = pos;
      result.neg = neg;
      return result;
   };

   function sign(a) {
      return Math.sign((a.pos >>> 0) - (a.neg >>> 0));
   };

   function sub(a, b) {
      return add(a, neg(b));
   };

   function tritabs(a) {
      let result = Object.create(ctor.prototype);
      result.pos = a.pos | a.neg;
      result.neg = 0;
      return result;
   };

   function tritadd(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = b.pos | 0;
      let neg_B = b.neg | 0;
      let pos_XOR = pos_A ^ pos_B;
      let neg_XOR = neg_A ^ neg_B;
      let t = pos_XOR & neg_XOR;
      let pos_AND = pos_A & pos_B;
      let neg_AND = neg_A & neg_B;
      let result = Object.create(ctor.prototype);
      result.pos = neg_AND | (pos_XOR ^ t);
      result.neg = pos_AND | (neg_XOR ^ t);
      return result;
   };

   function tritany(a, b) {
      let pos_OR = a.pos | b.pos;
      let neg_OR = a.neg | b.neg;
      let t = pos_OR & neg_OR;
      let result = Object.create(ctor.prototype);
      result.pos = pos_OR ^ t;
      result.neg = neg_OR ^ t;
      return result;
   };

   function tritcmp(a, b) {
      return tritany(a, neg(b));
   };

   function tritcons(a, b) {
      let result = Object.create(ctor.prototype);
      result.pos = a.pos & b.pos;
      result.neg = a.neg & b.neg;
      return result;
   };

   function tritdec(a) {
      return neg(tritinc(neg(a)));
   };

   function triteq(a, b) {
      let neg = (a.pos ^ b.pos) | (a.neg ^ b.neg);
      let result = Object.create(ctor.prototype);
      result.pos = ~neg;
      result.neg = neg;
      return result;
   };

   function tritgt(a, b) {
      return tritlt(b, a);
   };

   function tritgte(a, b) {
      return neg(tritlt(a, b));
   };

   function tritinc(a) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let result = Object.create(ctor.prototype);
      result.pos = ~(pos_A | neg_A);
      result.neg = pos_A;
      return result;
   };

   function tritlt(a, b) {
      let pos = (~a.pos & b.pos) | (a.neg & ~b.neg);
      let result = Object.create(ctor.prototype);
      result.pos = pos;
      result.neg = ~pos;
      return result;
   };

   function tritlte(a, b) {
      return neg(tritlt(b, a));
   };

   function tritmax(a, b) {
      let result = Object.create(ctor.prototype);
      result.pos = a.pos | b.pos;
      result.neg = a.neg & b.neg;
      return result;
   };

   function tritmin(a, b) {
      let result = Object.create(ctor.prototype);
      result.pos = a.pos & b.pos;
      result.neg = a.neg | b.neg;
      return result;
   };

   function tritmul(a, b) {
      let pos_A = a.pos | 0;
      let neg_A = a.neg | 0;
      let pos_B = a.pos | 0;
      let neg_B = a.neg | 0;
      let result = Object.create(ctor.prototype);
      result.pos = (pos_A & pos_B) | (neg_A & neg_B);
      result.neg = (pos_A & neg_B) | (neg_A & pos_B);
      return result;
   };

   function tritnabs(a) {
      return neg(tritabs(a));
   };

   function tritnadd(a, b) {
      return neg(tritadd(a, b));
   };

   function tritneg(a) {
      return tritpos(neg(a));
   };
   
   function tritneq(a, b) {
      return neg(tritneq(a, b));
   };

   function tritnmax(a, b) {
      return neg(tritmax(a, b));
   };

   function tritnmin(a, b) {
      return neg(tritmin(a, b));
   };

   function tritnmul(a, b) {
      return neg(tritmul(a, b));
   };

   function tritnneg(a) {
      return neg(tritneg(a));
   };

   function tritnpos(a) {
      return neg(tritpos(a));
   };

   function tritnzero(a) {
      return neg(tritzero(a));
   };

   function tritpos(a) {
      a = a.pos;
      let result = Object.create(ctor.prototype);
      result.pos = a;
      result.neg = ~a;
      return result;
   };

   function tritsub(a, b) {
      return tritadd(a, neg(b));
   };

   function tritzero(a) {
      a = a.pos | a.neg;
      let result = Object.create(ctor.prototype);
      result.pos = ~a;
      result.neg = a;
      return result;
   };

   function toBalanced(a, tab) {
      let pos_A = a.pos;
      let neg_A = a.neg;
      let result = "";
      for (let i = 1 << 31; i; i >>>= 1) {
         result += tab[(pos_A & i) ? 2 : +!(neg_A & i)];
      }
      return result;
   };

   function valueOf(a) {
      let pos = a.pos | 0;
      let neg = a.neg | 0;
      let result = 0;
      for (let i = 1; pos || neg; i *= 3) {
         result += i * ((pos & 1) - (neg & 1));
         pos >>>= 1;
         neg >>>= 1;
      }
      return result;
   };

   ctor.MAX_VALUE = Object.freeze(ctor(MAX_VALUE));
   ctor.MIN_VALUE = Object.freeze(ctor(MIN_VALUE));
   ctor.ZERO = Object.freeze(ctor(0));
   ctor.abs = function(a, b) { return abs(cast(a)); };
   ctor.add = function(a, b) { return add(cast(a), cast(b)); };
   ctor.addcarry = function(a, b, c) { return addcarry(cast(a), cast(b), +c); };
   ctor.addext = function(a, b) { return addext(cast(a), cast(b)); };
   ctor.cast = cast;
   ctor.cldiv = function(a, b) { return cldiv(cast(a), cast(b)); };
   ctor.clmul = function(a, b) { return clmul(cast(a), cast(b)); };
   ctor.clmulinv = function(a) { return clmulinv(cast(a)); };
   ctor.clpow = function(a, b) { return clpow(cast(a), Math.trunc(b)); };
   ctor.clrem = function(a, b) { return clrem(cast(a), cast(b)); };
   ctor.clz32 = function(a) { return clz32(cast(a)); };
   ctor.cmp = function(a, b) { return cmp(cast(a), cast(b)); };
   ctor.ctz32 = function(a) { return ctz32(cast(a)); };
   ctor.dec = function(a, b) { return dec(cast(a)); };
   ctor.div = function(a, b) { return div(cast(a), cast(b)); };
   ctor.eq = function(a, b) { return !cmp(cast(a), cast(b)); };
   ctor.gt = function(a, b) { return cmp(cast(a), cast(b)) > 0; };
   ctor.gte = function(a, b) { return cmp(cast(a), cast(b)) >= 0; };
   ctor.inc = function(a, b) { return inc(cast(a)); };
   ctor.iseven = function(a) { return !parity(cast(a)); };
   ctor.isneg = function(a) { return sign(cast(a)) < 0; };
   ctor.isodd = function(a) { return !!parity(cast(a)); };
   ctor.ispos = function(a) { return sign(cast(a)) > 0; };
   ctor.iszero = function(a) { return !sign(cast(a)); };
   ctor.lt = function(a, b) { return cmp(cast(a), cast(b)) < 0; };
   ctor.lte = function(a, b) { return cmp(cast(a), cast(b)) <= 0; };
   ctor.max = function(a) { return max(cast(a), cast(b)); };
   ctor.min = function(a) { return min(cast(a), cast(b)); };
   ctor.mul = function(a, b) { return mul(cast(a), cast(b)); };
   ctor.mulext = function(a, b) { return mulext(cast(a), cast(b)); };
   ctor.mulinv = function(a) { return mulinv(cast(a)); };
   ctor.nabs = function(a) { return nabs(cast(a)); };
   ctor.nadd = function(a, b) { return nadd(cast(a), cast(b)); };
   ctor.neg = function(a) { return neg(cast(a)); };
   ctor.neq = function(a, b) { return !!cmp(cast(a), cast(b)); };
   ctor.nmax = function(a, b) { return nmax(cast(a, b)); };
   ctor.nmin = function(a, b) { return nmin(cast(a, b)); };
   ctor.nmul = function(a, b) { return nmul(cast(a, b)); };
   ctor.pow = function(a, b) { return pow(cast(a), Math.trunc(b)); };
   ctor.rem = function(a, b) { return rem(cast(a), cast(b)); };
   ctor.shift = function(a, n) { return shift(cast(a), Math.trunc(n)); };
   ctor.sign = function(a) { return sign(cast(a)); };
   ctor.sub = function(a, b) { return sub(cast(a), cast(b)); };
   ctor.tritabs = function(a) { return tritabs(cast(a)); };
   ctor.tritadd = function(a, b) { return tritadd(cast(a), cast(b)); };
   ctor.tritany = function(a, b) { return tritany(cast(a), cast(b)); };
   ctor.tritcmp = function(a, b) { return tritcmp(cast(a), cast(b)); };
   ctor.tritcons = function(a, b) { return tritcons(cast(a), cast(b)); };
   ctor.tritdec = function(a) { return tritdec(cast(a)); };
   ctor.triteq = function(a, b) { return triteq(cast(a), cast(b)); };
   ctor.tritgt = function(a, b) { return tritgt(cast(a), cast(b)); };
   ctor.tritgte = function(a, b) { return tritgte(cast(a), cast(b)); };
   ctor.tritinc = function(a) { return tritinc(cast(a)); };
   ctor.tritlt = function(a, b) { return tritlt(cast(a), cast(b)); };
   ctor.tritlte = function(a, b) { return tritlte(cast(a), cast(b)); };
   ctor.tritmax = function(a, b) { return tritmax(cast(a), cast(b)); };
   ctor.tritmin = function(a, b) { return tritmin(cast(a), cast(b)); };
   ctor.tritmul = function(a, b) { return tritmul(cast(a), cast(b)); };
   ctor.tritnabs = function(a, b) { return tritnabs(cast(a), cast(b)); };
   ctor.tritnadd = function(a, b) { return tritnadd(cast(a), cast(b)); };
   ctor.tritneg = function(a) { return tritneg(cast(a)); };
   ctor.tritneq = function(a, b) { return tritneq(cast(a), cast(b)); };
   ctor.tritnmax = function(a, b) { return tritnmax(cast(a), cast(b)); };
   ctor.tritnmin = function(a, b) { return tritnmin(cast(a), cast(b)); };
   ctor.tritnmul = function(a, b) { return tritnmul(cast(a), cast(b)); };
   ctor.tritnneg = function(a) { return tritnneg(cast(a)); };
   ctor.tritnpos = function(a) { return tritnpos(cast(a)); };
   ctor.tritnzero = function(a) { return tritnzero(cast(a)); };
   ctor.tritpos = function(a) { return tritpos(cast(a)); };
   ctor.tritsub = function(a, b) { return tritsub(cast(a), cast(b)); };
   ctor.tritzero = function(a) { return tritzero(cast(a)); };
   ctor.prototype.toBalanced = function(tab) { return toBalanced(this, String(tab == null ? "T01" : tab).split("")); };
   ctor.prototype.toString = function(radix) { return valueOf(this).toString(radix); };
   ctor.prototype.valueOf = function() { return valueOf(this); };

   return ctor;
})();


02 May 2024 05:04
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22732
Location: Silicon Valley
Reply with quote
Thanks!

Do you have a website where it's already running as part of some web app?

_________________
https://mastodon.social/@Shaos :dj:
https://www.youtube.com/@Shaos1973


03 May 2024 09:03
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 2 posts ] 

Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.