class tally {
constructor(value, bytes) {
if (value instanceof tally) {
this.buf = value.buf
this.a32 = new Uint32Array(this.buf);
this.a16 = new Uint16Array(this.buf);
this.a8 = new Uint8Array(this.buf);
} else {
if (value.buffer instanceof ArrayBuffer) {
this.buf = value.buffer
this.a32 = new Uint32Array(this.buf);
this.a16 = new Uint16Array(this.buf);
this.a8 = new Uint8Array(this.buf);
} else {
this.buf = new ArrayBuffer(bytes);
this.a32 = new Uint32Array(this.buf);
this.a16 = new Uint16Array(this.buf);
this.a8 = new Uint8Array(this.buf);
let c = value
for (let i = 0 ; i<bytes ; i++) {
this.a32[i] = c % values.max32
c = Math.floor(c / values.max32)
}
}
}
}
static add(a, b) {
let l = Math.max(a.a32.byteLength, b.a32.byteLength)
let c = new tally(0, l+4 )
for (let i=0;i<Math.ceil(l/4);i++) {
let t = a.a32[i] + b.a32[i]
if (t > (values.max32 - 1)){
c.a32[i+1] = 1
}
c.a32[i] = c.a32[i] + t;
}
if (c.a32[l]) {
logger.log("overflow")
return c;
}
return new tally(c.a32.slice(0, c.a32.length-1), l);
}
static mul(a, b) {
let l = a.a32.byteLength + b.a32.byteLength
let c = new tally(0, l)
let carry,temp
for (let i=0; i<a.a16.length; i++) {
carry = 0
for (let j=0; j<b.a16.length; j++) {
temp = c.a16[i + j] + carry + a.a16[i] * b.a16[j]
carry = Math.floor(temp / MAX_VALUES.max16)
c.a16[i + j] = temp % MAX_VALUES.max16
// c[i + j] = c[i + j] mod base
}
c.a16[i + a.a16.length] = carry
}
if (carry)logger.log("overflow")
return new tally(c.a16.slice(0, a.a16.length));
}
static sub(a,b){
let l = Math.max(a.a32.byteLength, b.a32.byteLength)
let c = new tally(0, l)
for (let i=0;i<Math.ceil(l/4);i++) {
let u = a.a32[i]<b.a32[i]
let t = a.a32[i]
if (u) {
a = tally._carry(a,i)
t = t + MAX_VALUES.max32
}
c.a32[i] = t - b.a32[i]
}
return c;
}
static _carry(a,i){
if (i === a.a32.length) return a
a.a32[i+1] = a.a32[i+1] - 1
if (a.a32[i+1] === MAX_VALUES.max32-1) {
return tally._carry(a,i+1)
}
return a
}
// static sub16(a,b){ // maybe NOT needed
// let c = new Uint16Array(16)
// //let carry = new Uint16Array(1);
// for (let i=0;i<c.length;i++) {
// let u = a[i]<b[i]
// let t = a[i]
// if (u) {
// a = this._carry16(a,i)
// t = t + Math.pow(2, 16)
// }
// c[i] = a[i]-b[i]
// }
// return c;
// }
// static _carry16(a,i){
// if (i+1 === a.length) return a
// a[i+1] = a[i+1] - 1
// if (a[i+1] === 0xffff) {
// return this._carry(a,i+1)
// }
// return a
// }
static _div(a, b){
// let cat = new tally(0, a.a32.byteLength)
// let set = new tally(0, a.a32.byteLength)
let cat = new Uint16Array(16);
let set = new Uint16Array(16);
if (tally._iszero(b) || tally._iszero(a)) {
// return [cat, set];
return [new tally(0, 32), new tally(0, 32)]
}
if (tally._gt(b,a,b.a16.length-1)) {
// return [cat, new tally(a.a16.slice(0), a.a16.byteLength)];
return [new tally(0, 32), new tally(a.a16.slice(0), a.a16.byteLength)];
}
function shr (n) {
const len = 14;
for (let i = len; i >= 0; i--) {
n[i + 1] = n[i];
}
n[0] = 0;
return n;
}
const slen = significantLength(b.a16);
const slena = significantLength(a.a16);
let pos = slena - slen;
for (let i = 0; i < slen; i++) {
set[i] = a.a16[i + pos];
}
const [n, c] = tally._findDiv(set, b);
cat[0] = n;
set = c.a16;
let reps = 0;
while (pos > 0) {
reps ++;
if (tally._gt(b, new tally(set), b.a16.length - 1)) {
set = shr(set);
pos --;
set[0] = a.a16[pos];
}
const [n, c] = tally._findDiv(set, b);
cat = shr(cat);
cat[0] = n;
set = c.a16;
if (reps > 40) return [new tally(cat), new tally(set)]
}
return [new tally(cat), new tally(set)]
}
// n1 > n2
// n1.length <= n2.length + 1
static _findDiv(n1, t2) {
const n2 = t2.a16;
const t1 = new tally(n1);
const len1 = significantLength(n1);
const len2 = significantLength(n2);
let catMax;
if (len1 < len2) throw new Error('_findDiv n1 < n2');
if (len2 === len1) catMax = Math.floor(n1[len1 - 1] / n2[len2-1]);
else {
const divident = n1[len1 - 1] * MAX_VALUES.max16 + n1[len1 - 2];
const cat = Math.floor(divident / n2[len2-1]);
catMax = cat < MAX_VALUES.max16 ? cat : MAX_VALUES.max16 - 1;
}
const prod1 = tally.mul(t2, new tally(catMax, 32));
if (tally._eq(prod1, t1)) return [catMax, new tally(0, 32)];
if (tally._lt(prod1, t1, prod1.a16.length - 1)) return [catMax, tally.sub(t1, prod1)];
catMax -= 1;
return [catMax, tally.sub(t1, tally.mul(t2, new tally(catMax, 32)))];
}
static mod(a, b){
let c = tally._div(a,b)
//p(q,r)
return c[1];
}
static div(a, b){
let c = tally._div2(a,b)
//p(q,r)
return c;
}
static addmod(a, b, c){
let d = tally.add(a, b)
let e = tally._div(d,c)
return e[1];
}
static mulmod(a, b, c){
let d = tally.mul(a,b)
let e = tally._div(d,c)
return e[1];
}
static lt(a, b) {
let c = new tally(0, a.a32.byteLength)
c.a8[0] = tally._lt(a,b,a.a32.length-1)? 1:0
return c;
}
static _lt(a, b, i) {
//logger.log(a,b,i)
if (i === -1) return false
if (b.a32[i] < a.a32[i]) return false
if (b.a32[i] == a.a32[i]) return (true && tally._lt(a, b, i-1))
return true;
}
static gt(a, b){
let c = new tally(0, a.a32.byteLength)
c.a8[0] = tally._gt(a,b,a.a32.length-1)? 1:0
return c
}
static _gt(a, b, i){
// logger.log("abi ",a[i],b[i],i)
if (i === -1) return false
if (b.a32[i] > a.a32[i]) return false
if (b.a32[i] == a.a32[i]) return (true && tally._gt(a, b, i-1))
return true;
}
static eq(a, b){
let c = new tally(0, a.a32.byteLength)
c.a8[0] = tally._eq(a, b)? 1 : 0
//p(t,a,b,c)
return c;
}
static _eq(a,b){
let t = true
let l = Math.max(a.a32.length, b.a32.length)
for (let i=0;i<l;i++) {
t = t && b.a32[i] === a.a32[i]
}
return t
}
static iszero(a){
let c = new tally(0, a.a32.byteLength)
c.a8[0] = tally._iszero(a)
return c;
}
static _iszero(a){
let t = true
for (let i=0; i < a.a32.length; i++) {
t = t && a.a32[i] === 0
}
return t
}
static _isone(a){ // ---
let t = true
for (let i=1; i < a.a32.length; i++) {
t = t && a.a32[i] === 0
}
return a.a32[0] ==1 ? t: false;
}
static and(a, b){
let f = (a, b) => a & b
return tally._bit2(a, b, f)
}
static _bit2(a, b, fx){
let c = new tally(0, a.a32.byteLength)
for (let i=0;i<c.a32.length;i++) {
c.a32[i] = fx(a.a32[i], b.a32[i])
}
return c;
}
static or(a, b){
let f = (a, b) => a | b
return tally._bit2(a, b, f)
}
static xor(a, b){
let f = (a, b) => a ^ b
return tally._bit2(a, b, f)
}
static not(a){
let b = new tally(0, a.a32.byteLength)
for (let i=0;i<a.a32.length;i++) {
b.a32[i] = ~ a.a32[i]
}
return b
}
static shl(a, b){
let c = new tally(0, a.a32.byteLength + 4)
for (let i=0; i<a.a32.length; i++) {
let t = a.a32[i] * Math.pow(2,b.a8[0])
c.a32[i] = t % MAX_VALUES.max32
c.a32[i+1] = c.a32[i+1] + t/MAX_VALUES.max32;
}
return c
}
static shr(a, b){
let c = new tally(0, a.a32.byteLength + 4)
for (let i=a.a32.length; i>-1; i--) {
let t = Math.floor(a.a32[i-1] / Math.pow(2,b.a8[0]))
c.a32[i] = t
let t2 = a.a32[i-1] % Math.pow(2,b.a8[0])
c.a32[i-1] = c.a32[i-1] + t2*MAX_VALUES.max32/Math.pow(2,b.a8[0]);
}
return new tally(c.a32.slice(1), a.a32.byteLength);
}
static empty(length = 32) {
return new tally(0, length);
}
static neg(a) {
return tally.sub(tally.empty(), a);
}
static isNeg(a) { // ---
return tally._isNeg(a)? new tally(1, 32) : new tally(0, 32);
}
static _isNeg(a) { // ---
return (a.a32[a.a32.length - 1] > 0xefffffff);
}
static abs(a) { // ---
return tally._isNeg(a)? tally.neg(a) : a;
}
toString (encoding, size) {
// encoding = encoding || 16;
// size = size || this.a8.byteLength;
// const arr = this.a8.slice(0, size).reverse();
// return u8ToString(arr, 'base' + encoding);
return this.a8;
}
clone(){
let f = this.a8.slice(0)
return new tally(f)
}
static _div2(a2, b2){
let a = a2
let b = b2
if (tally._iszero(b) || tally._iszero(a) ) {
return [new tally(0, 32), new tally(a.a16.slice(0), a.a16.byteLength)]
}
let q = new tally(0, 32);
let r = new tally(0, 32);
let m = new tally(0, 32);
let bb = 0 , lb, la
let qq
for (let y = b.a16.length-1; y>-1; y--) {
bb = b.a16[y]? b.a16[y] : bb
lb = (!bb)? b.a16.length-y: lb
}
for (let i = (a.a16.length-1); i>-1; i--) {
//if (!m.a16[i+1]) {
for (let j = (a.a16.length-1); j>0; j--) {
m.a16[j] = m.a16[j-1]
}
m.a16[0]= a.a16[i]
//}
console.log("bb",bb, i, m.a16[0], m.a16[i],m.a16[i+1])
if (m.a16[0]>bb || m.a16[1]>0) {
let q2 = new tally(0,32)
let t1 = 0, t2 = 0
if (i < a.a16.length -1) t1 = m.a16[1]
let t = t1*values.max16 + m.a16[0]
q2.a16[i] = Math.floor(t / bb)
let n = tally.mul(b ,q2)
let k = tally._gt(n,a,a.a32.length-1)
if (k) {
q2.a16[i] = q2.a16[i] - 1
n = tally.mul(b ,q2)
}
la = la? la : i
//a = tally.sub(a, n)
m.a16[1] = 0
m.a16[0] = t - bb*q2.a16[i]
let a1 = tally.sub(a, n)
a = a1
q.a16[i-(15-la+lb)] = q2.a16[i]
}
//r.a16[0] = m.a16[0]
//logger.log("a,a1,i!!?!!",i,a.a16.toString(),a1.a16.toString())
}
// for (let j = (q.a16.length-1); j>0; j--) {
// q.a16[la - lb -j] = q.a16[j]
// }
console.log(la,lb,a, b, q);
return [q, a];
}
static rand(l) { // ---
let arr8 = new Uint8Array(l)
for (let i=0; i<l; i++) {
arr8[i] = Math.floor(Math.random()*255)
}
return new tally(arr8);
}
static gcd(a, b) { // ---
//logger.log("gcd ",a, b,tally._gt(a, b, a.a32.length-1))
mutable count_loops ++;
if (tally._iszero(b)) return a;
if (tally._iszero(a)) return b;
if (tally._gt(a, b, a.a32.length-1)) {
return tally.gcd(tally.sub(a, b), b);
} else {
return tally.gcd(a, tally.sub(b, a));
}
}
static lcm(a, b) { // ---
return tally.div(tally.mul(a, b), tally.gcd(a, b))
}
static isEven(a) { // ---
return (a.a8[0] & 1) === 0;
};
static isOdd(a) { // ---
return (a.a8[0] & 1) === 1;
};
}