Javascript implementation of balanced ternary

Balanced Ternary Numeral System - forum was moved from http://ternary.info

Moderator: haqreu

PHPBB12345
Junior
Posts: 1
Joined: 02 May 2024 05:02

Javascript implementation of balanced ternary

Post by PHPBB12345 »

Code: Select all

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;
})();
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Javascript implementation of balanced ternary

Post by Shaos »

Thanks!

Do you have a website where it's already running as part of some web app?
Я тут за главного - если что шлите мыло на me собака shaos точка net