Restructured the repository into a monorepo to better organize application code and maintenance scripts. ## Workspace Structure - web-app: Next.js application (all app code moved from root) - housekeeping: Database backup and maintenance scripts ## Key Changes - Moved all application code to web-app/ using git mv - Moved database scripts to housekeeping/ workspace - Updated Dockerfile for monorepo build process - Updated docker-compose files (volume paths: ./web-app/etc/hosts/) - Updated .gitignore for workspace-level node_modules - Updated documentation (README.md, CLAUDE.md, CHANGELOG.md) ## Migration Impact - Root package.json now manages workspaces - Build commands delegate to web-app workspace - All file history preserved via git mv - Docker build process updated for workspace structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
958 lines
24 KiB
TypeScript
958 lines
24 KiB
TypeScript
/**
|
|
* Binary Calculator (BC) Arbitrary Precision Mathematics Lib v0.10 (LGPL)
|
|
* Copy of libbcmath included in PHP5 src
|
|
* supports bcadd, bcsub, bcmul, bcdiv, bccomp, bcscale, and new function bcround(val, precision)
|
|
* See PHP Manual for parameters.. functions work identical to the PHP5 funcions
|
|
* Feel free to use how-ever you want, just email any bug-fixes/improvements to the sourceforge project:
|
|
* https://sourceforge.net/projects/bcmath-js/
|
|
*
|
|
* Ported from the PHP5 bcmath extension source code,
|
|
* which uses the libbcmath package...
|
|
* Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
|
|
* Copyright (C) 2000 Philip A. Nelson
|
|
* The Free Software Foundation, Inc.
|
|
* 59 Temple Place, Suite 330
|
|
* Boston, MA 02111-1307 USA.
|
|
* e-mail: philnelson@acm.org
|
|
* us-mail: Philip A. Nelson
|
|
* Computer Science Department, 9062
|
|
* Western Washington University
|
|
* Bellingham, WA 98226-9062
|
|
*/
|
|
|
|
interface BCNum {
|
|
n_sign: string | null;
|
|
n_len: number | null;
|
|
n_scale: number | null;
|
|
n_value: number[] | null;
|
|
toString(): string;
|
|
setScale(scale: number): BCNum;
|
|
}
|
|
|
|
type BCNumValue = string | number;
|
|
|
|
const libbcmath = {
|
|
PLUS: "+" as const,
|
|
MINUS: "-" as const,
|
|
BASE: 10,
|
|
scale: 0,
|
|
bc_num: function (this: BCNum): void {
|
|
this.n_sign = null;
|
|
this.n_len = null;
|
|
this.n_scale = null;
|
|
this.n_value = null;
|
|
this.toString = function (): string {
|
|
let b: string, a: string;
|
|
a = this.n_value!.join("");
|
|
b =
|
|
(this.n_sign === libbcmath.PLUS ? "" : this.n_sign) +
|
|
a.substr(0, this.n_len!);
|
|
if (this.n_scale! > 0) {
|
|
b += "." + a.substr(this.n_len!, this.n_scale!);
|
|
}
|
|
return b;
|
|
};
|
|
this.setScale = function (a: number): BCNum {
|
|
while (this.n_scale! < a) {
|
|
this.n_value!.push(0);
|
|
this.n_scale!++;
|
|
}
|
|
while (this.n_scale! > a) {
|
|
this.n_value!.pop();
|
|
this.n_scale!--;
|
|
}
|
|
return this;
|
|
};
|
|
} as any as { new (): BCNum },
|
|
bc_new_num: function (b: number, c: number): BCNum {
|
|
const a = new libbcmath.bc_num();
|
|
a.n_sign = libbcmath.PLUS;
|
|
a.n_len = b;
|
|
a.n_scale = c;
|
|
a.n_value = libbcmath.safe_emalloc(1, b + c, 0);
|
|
libbcmath.memset(a.n_value, 0, 0, b + c);
|
|
return a;
|
|
},
|
|
safe_emalloc: function (c: number, b: number, a: number): number[] {
|
|
return Array(c * b + a);
|
|
},
|
|
bc_init_num: function (): BCNum {
|
|
return libbcmath.bc_new_num(1, 0);
|
|
},
|
|
_bc_rm_leading_zeros: function (a: BCNum): void {
|
|
while (a.n_value![0] === 0 && a.n_len! > 1) {
|
|
a.n_value!.shift();
|
|
a.n_len!--;
|
|
}
|
|
},
|
|
php_str2num: function (b: string): BCNum {
|
|
const a = b.indexOf(".");
|
|
if (a === -1) {
|
|
return libbcmath.bc_str2num(b, 0);
|
|
} else {
|
|
return libbcmath.bc_str2num(b, b.length - a);
|
|
}
|
|
},
|
|
CH_VAL: function (a: string): number {
|
|
return parseInt(a, 10);
|
|
},
|
|
BCD_CHAR: function (a: number): string {
|
|
return a + "0";
|
|
},
|
|
isdigit: function (a: string): boolean {
|
|
return !isNaN(parseInt(a, 10));
|
|
},
|
|
bc_str2num: function (h: string, c: number): BCNum {
|
|
const g = h.split("");
|
|
let a = 0;
|
|
let b = 0;
|
|
let e = 0;
|
|
let i = false;
|
|
if (g[a] === "+" || g[a] === "-") {
|
|
a++;
|
|
}
|
|
while (g[a] === "0") {
|
|
a++;
|
|
}
|
|
while (g[a] && !isNaN(parseInt(g[a], 10))) {
|
|
a++;
|
|
b++;
|
|
}
|
|
if (g[a] === ".") {
|
|
a++;
|
|
}
|
|
while (g[a] && !isNaN(parseInt(g[a], 10))) {
|
|
a++;
|
|
e++;
|
|
}
|
|
if (g[a] || b + e === 0) {
|
|
return libbcmath.bc_init_num();
|
|
}
|
|
e = libbcmath.MIN(e, c);
|
|
if (b === 0) {
|
|
i = true;
|
|
b = 1;
|
|
}
|
|
const f = libbcmath.bc_new_num(b, e);
|
|
a = 0;
|
|
if (g[a] === "-") {
|
|
f.n_sign = libbcmath.MINUS;
|
|
a++;
|
|
} else {
|
|
f.n_sign = libbcmath.PLUS;
|
|
if (g[a] === "+") {
|
|
a++;
|
|
}
|
|
}
|
|
while (g[a] === "0") {
|
|
a++;
|
|
}
|
|
let d = 0;
|
|
if (i) {
|
|
f.n_value![d++] = 0;
|
|
b = 0;
|
|
}
|
|
for (; b > 0; b--) {
|
|
f.n_value![d++] = libbcmath.CH_VAL(g[a++]);
|
|
}
|
|
if (e > 0) {
|
|
a++;
|
|
for (; e > 0; e--) {
|
|
f.n_value![d++] = libbcmath.CH_VAL(g[a++]);
|
|
}
|
|
}
|
|
return f;
|
|
},
|
|
cint: function (b?: number): number {
|
|
if (typeof b === "undefined") {
|
|
b = 0;
|
|
}
|
|
const a = parseInt(b.toString(), 10);
|
|
if (isNaN(a)) {
|
|
return 0;
|
|
}
|
|
return a;
|
|
},
|
|
MIN: function (d: number, c: number): number {
|
|
return d > c ? c : d;
|
|
},
|
|
MAX: function (d: number, c: number): number {
|
|
return d > c ? d : c;
|
|
},
|
|
ODD: function (b: number): number {
|
|
return b & 1;
|
|
},
|
|
memset: function (d: number[], e: number, c: number, a: number): void {
|
|
for (let b = 0; b < a; b++) {
|
|
d[e + b] = c;
|
|
}
|
|
},
|
|
memcpy: function (
|
|
b: number[],
|
|
f: number,
|
|
e: number[],
|
|
d: number,
|
|
a: number
|
|
): boolean {
|
|
for (let c = 0; c < a; c++) {
|
|
b[f + c] = e[d + c];
|
|
}
|
|
return true;
|
|
},
|
|
bc_is_zero: function (a: BCNum): boolean {
|
|
let b = a.n_len! + a.n_scale!;
|
|
let c = 0;
|
|
while (b > 0 && a.n_value![c++] === 0) {
|
|
b--;
|
|
}
|
|
return b === 0;
|
|
},
|
|
bc_out_of_memory: function (): never {
|
|
throw new Error("(BC) Out of memory");
|
|
},
|
|
bc_add: function (f: BCNum, d: BCNum, c: number): BCNum {
|
|
let e: BCNum;
|
|
if (f.n_sign === d.n_sign) {
|
|
e = libbcmath._bc_do_add(f, d, c);
|
|
e.n_sign = f.n_sign;
|
|
} else {
|
|
const b = libbcmath._bc_do_compare(f, d, false, false);
|
|
switch (b) {
|
|
case -1:
|
|
e = libbcmath._bc_do_sub(d, f, c);
|
|
e.n_sign = d.n_sign;
|
|
break;
|
|
case 0:
|
|
const a = libbcmath.MAX(c, libbcmath.MAX(f.n_scale!, d.n_scale!));
|
|
e = libbcmath.bc_new_num(1, a);
|
|
libbcmath.memset(e.n_value!, 0, 0, a + 1);
|
|
break;
|
|
case 1:
|
|
e = libbcmath._bc_do_sub(f, d, c);
|
|
e.n_sign = f.n_sign;
|
|
break;
|
|
default:
|
|
e = libbcmath.bc_init_num();
|
|
}
|
|
}
|
|
return e;
|
|
},
|
|
bc_compare: function (b: BCNum, a: BCNum): number {
|
|
return libbcmath._bc_do_compare(b, a, true, false);
|
|
},
|
|
_bc_do_compare: function (
|
|
e: BCNum,
|
|
d: BCNum,
|
|
c: boolean,
|
|
b: boolean
|
|
): number {
|
|
if (c && e.n_sign !== d.n_sign) {
|
|
if (e.n_sign === libbcmath.PLUS) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
if (e.n_len !== d.n_len) {
|
|
if (e.n_len! > d.n_len!) {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
let f = e.n_len! + Math.min(e.n_scale!, d.n_scale!);
|
|
let g = 0;
|
|
let a = 0;
|
|
while (f > 0 && e.n_value![g] === d.n_value![a]) {
|
|
g++;
|
|
a++;
|
|
f--;
|
|
}
|
|
if (b && f === 1 && e.n_scale === d.n_scale) {
|
|
return 0;
|
|
}
|
|
if (f !== 0) {
|
|
if (e.n_value![g] > d.n_value![a]) {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
if (e.n_scale !== d.n_scale) {
|
|
if (e.n_scale! > d.n_scale!) {
|
|
for (f = e.n_scale! - d.n_scale!; f > 0; f--) {
|
|
if (e.n_value![g++] !== 0) {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (f = d.n_scale! - e.n_scale!; f > 0; f--) {
|
|
if (d.n_value![a++] !== 0) {
|
|
if (!c || e.n_sign === libbcmath.PLUS) {
|
|
return -1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
},
|
|
_one_mult: function (
|
|
d: number[],
|
|
e: number,
|
|
i: number,
|
|
f: number,
|
|
j: number[],
|
|
c: number
|
|
): void {
|
|
if (f === 0) {
|
|
libbcmath.memset(j, 0, 0, i);
|
|
} else {
|
|
if (f === 1) {
|
|
libbcmath.memcpy(j, c, d, e, i);
|
|
} else {
|
|
let b = e + i - 1;
|
|
let a = c + i - 1;
|
|
let h = 0;
|
|
while (i-- > 0) {
|
|
const g = d[b--] * f + h;
|
|
j[a--] = g % libbcmath.BASE;
|
|
h = Math.floor(g / libbcmath.BASE);
|
|
}
|
|
if (h !== 0) {
|
|
j[a] = h;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
bc_divide: function (l: BCNum, k: BCNum, z: number): BCNum | -1 {
|
|
if (libbcmath.bc_is_zero(k)) {
|
|
return -1;
|
|
}
|
|
if (libbcmath.bc_is_zero(l)) {
|
|
return libbcmath.bc_new_num(1, z);
|
|
}
|
|
let w: BCNum | undefined;
|
|
if (k.n_scale === 0) {
|
|
if (k.n_len === 1 && k.n_value![0] === 1) {
|
|
w = libbcmath.bc_new_num(l.n_len!, z);
|
|
w.n_sign = l.n_sign === k.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
|
libbcmath.memset(w.n_value!, l.n_len!, 0, z);
|
|
libbcmath.memcpy(
|
|
w.n_value!,
|
|
0,
|
|
l.n_value!,
|
|
0,
|
|
l.n_len! + libbcmath.MIN(l.n_scale!, z)
|
|
);
|
|
return w;
|
|
}
|
|
}
|
|
let s = k.n_scale!;
|
|
let h = k.n_len! + s - 1;
|
|
while (s > 0 && k.n_value![h--] === 0) {
|
|
s--;
|
|
}
|
|
const j = l.n_len! + s;
|
|
const u = l.n_scale! - s;
|
|
let a: number;
|
|
if (u < z) {
|
|
a = z - u;
|
|
} else {
|
|
a = 0;
|
|
}
|
|
const c = libbcmath.safe_emalloc(1, l.n_len! + l.n_scale!, a + 2);
|
|
if (c === null) {
|
|
libbcmath.bc_out_of_memory();
|
|
}
|
|
libbcmath.memset(c, 0, 0, l.n_len! + l.n_scale! + a + 2);
|
|
libbcmath.memcpy(c, 1, l.n_value!, 0, l.n_len! + l.n_scale!);
|
|
let i = k.n_len! + s;
|
|
const b = libbcmath.safe_emalloc(1, i, 1);
|
|
if (b === null) {
|
|
libbcmath.bc_out_of_memory();
|
|
}
|
|
libbcmath.memcpy(b, 0, k.n_value!, 0, i);
|
|
b[i] = 0;
|
|
h = 0;
|
|
while (b[h] === 0) {
|
|
h++;
|
|
i--;
|
|
}
|
|
let q: number;
|
|
let n: boolean;
|
|
if (i > j + z) {
|
|
q = z + 1;
|
|
n = true;
|
|
} else {
|
|
n = false;
|
|
if (i > j) {
|
|
q = z + 1;
|
|
} else {
|
|
q = j - i + z + 1;
|
|
}
|
|
}
|
|
w = libbcmath.bc_new_num(q - z, z);
|
|
libbcmath.memset(w.n_value!, 0, 0, q);
|
|
const e = libbcmath.safe_emalloc(1, i, 1);
|
|
if (e === null) {
|
|
libbcmath.bc_out_of_memory();
|
|
}
|
|
if (!n) {
|
|
const f = Math.floor(10 / (k.n_value![h] + 1));
|
|
if (f !== 1) {
|
|
libbcmath._one_mult(c, 0, j + u + a + 1, f, c, 0);
|
|
libbcmath._one_mult(k.n_value!, h, i, f, k.n_value!, h);
|
|
}
|
|
let r = 0;
|
|
let x: number;
|
|
if (i > j) {
|
|
x = i - j;
|
|
} else {
|
|
x = 0;
|
|
}
|
|
while (r <= j + z - i) {
|
|
let m: number;
|
|
if (k.n_value![h] === c[r]) {
|
|
m = 9;
|
|
} else {
|
|
m = Math.floor((c[r] * 10 + c[r + 1]) / k.n_value![h]);
|
|
}
|
|
if (
|
|
k.n_value![h + 1] * m >
|
|
(c[r] * 10 + c[r + 1] - k.n_value![h] * m) * 10 + c[r + 2]
|
|
) {
|
|
m--;
|
|
if (
|
|
k.n_value![h + 1] * m >
|
|
(c[r] * 10 + c[r + 1] - k.n_value![h] * m) * 10 + c[r + 2]
|
|
) {
|
|
m--;
|
|
}
|
|
}
|
|
let t = 0;
|
|
if (m !== 0) {
|
|
e[0] = 0;
|
|
libbcmath._one_mult(k.n_value!, h, i, m, e, 1);
|
|
let p = r + i;
|
|
let o = i;
|
|
for (let g = 0; g < i + 1; g++) {
|
|
let A: number;
|
|
if (o < 0) {
|
|
A = c[p] - 0 - t;
|
|
} else {
|
|
A = c[p] - e[o--] - t;
|
|
}
|
|
if (A < 0) {
|
|
A += 10;
|
|
t = 1;
|
|
} else {
|
|
t = 0;
|
|
}
|
|
c[p--] = A;
|
|
}
|
|
}
|
|
if (t === 1) {
|
|
m--;
|
|
let p = r + i;
|
|
let o = i - 1;
|
|
let v = 0;
|
|
for (let g = 0; g < i; g++) {
|
|
let A: number;
|
|
if (o < 0) {
|
|
A = c[p] + 0 + v;
|
|
} else {
|
|
A = c[p] + k.n_value![o--] + v;
|
|
}
|
|
if (A > 9) {
|
|
A -= 10;
|
|
v = 1;
|
|
} else {
|
|
v = 0;
|
|
}
|
|
c[p--] = A;
|
|
}
|
|
if (v === 1) {
|
|
c[p] = (c[p] + 1) % 10;
|
|
}
|
|
}
|
|
w.n_value![x++] = m;
|
|
r++;
|
|
}
|
|
}
|
|
w.n_sign = l.n_sign === k.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
|
if (libbcmath.bc_is_zero(w)) {
|
|
w.n_sign = libbcmath.PLUS;
|
|
}
|
|
libbcmath._bc_rm_leading_zeros(w);
|
|
return w;
|
|
},
|
|
_bc_do_add: function (h: BCNum, g: BCNum, i: number): BCNum {
|
|
const c = libbcmath.MAX(h.n_scale!, g.n_scale!);
|
|
const b = libbcmath.MAX(h.n_len!, g.n_len!) + 1;
|
|
const f = libbcmath.bc_new_num(b, libbcmath.MAX(c, i));
|
|
let l = h.n_scale!;
|
|
let a = g.n_scale!;
|
|
let k = h.n_len! + l - 1;
|
|
let e = g.n_len! + a - 1;
|
|
let j = c + b - 1;
|
|
if (l !== a) {
|
|
if (l > a) {
|
|
while (l > a) {
|
|
f.n_value![j--] = h.n_value![k--];
|
|
l--;
|
|
}
|
|
} else {
|
|
while (a > l) {
|
|
f.n_value![j--] = g.n_value![e--];
|
|
a--;
|
|
}
|
|
}
|
|
}
|
|
l += h.n_len!;
|
|
a += g.n_len!;
|
|
let m = 0;
|
|
while (l > 0 && a > 0) {
|
|
let d = h.n_value![k--] + g.n_value![e--] + m;
|
|
if (d >= libbcmath.BASE) {
|
|
m = 1;
|
|
d -= libbcmath.BASE;
|
|
} else {
|
|
m = 0;
|
|
}
|
|
f.n_value![j] = d;
|
|
j--;
|
|
l--;
|
|
a--;
|
|
}
|
|
if (l === 0) {
|
|
while (a-- > 0) {
|
|
let d = g.n_value![e--] + m;
|
|
if (d >= libbcmath.BASE) {
|
|
m = 1;
|
|
d -= libbcmath.BASE;
|
|
} else {
|
|
m = 0;
|
|
}
|
|
f.n_value![j--] = d;
|
|
}
|
|
} else {
|
|
while (l-- > 0) {
|
|
let d = h.n_value![k--] + m;
|
|
if (d >= libbcmath.BASE) {
|
|
m = 1;
|
|
d -= libbcmath.BASE;
|
|
} else {
|
|
m = 0;
|
|
}
|
|
f.n_value![j--] = d;
|
|
}
|
|
}
|
|
if (m === 1) {
|
|
f.n_value![j] += 1;
|
|
}
|
|
libbcmath._bc_rm_leading_zeros(f);
|
|
return f;
|
|
},
|
|
_bc_do_sub: function (h: BCNum, g: BCNum, i: number): BCNum {
|
|
const a = libbcmath.MAX(h.n_len!, g.n_len!);
|
|
const m = libbcmath.MAX(h.n_scale!, g.n_scale!);
|
|
const f = libbcmath.MIN(h.n_len!, g.n_len!);
|
|
const d = libbcmath.MIN(h.n_scale!, g.n_scale!);
|
|
const l = libbcmath.bc_new_num(a, libbcmath.MAX(m, i));
|
|
let k = h.n_len! + h.n_scale! - 1;
|
|
let c = g.n_len! + g.n_scale! - 1;
|
|
let n = a + m - 1;
|
|
let j = 0;
|
|
if (h.n_scale !== d) {
|
|
for (let e = h.n_scale! - d; e > 0; e--) {
|
|
l.n_value![n--] = h.n_value![k--];
|
|
}
|
|
} else {
|
|
for (let e = g.n_scale! - d; e > 0; e--) {
|
|
let b = 0 - g.n_value![c--] - j;
|
|
if (b < 0) {
|
|
b += libbcmath.BASE;
|
|
j = 1;
|
|
} else {
|
|
j = 0;
|
|
}
|
|
l.n_value![n--] = b;
|
|
}
|
|
}
|
|
for (let e = 0; e < f + d; e++) {
|
|
let b = h.n_value![k--] - g.n_value![c--] - j;
|
|
if (b < 0) {
|
|
b += libbcmath.BASE;
|
|
j = 1;
|
|
} else {
|
|
j = 0;
|
|
}
|
|
l.n_value![n--] = b;
|
|
}
|
|
if (a !== f) {
|
|
for (let e = a - f; e > 0; e--) {
|
|
let b = h.n_value![k--] - j;
|
|
if (b < 0) {
|
|
b += libbcmath.BASE;
|
|
j = 1;
|
|
} else {
|
|
j = 0;
|
|
}
|
|
l.n_value![n--] = b;
|
|
}
|
|
}
|
|
libbcmath._bc_rm_leading_zeros(l);
|
|
return l;
|
|
},
|
|
MUL_BASE_DIGITS: 80,
|
|
MUL_SMALL_DIGITS: 0,
|
|
bc_multiply: function (f: BCNum, d: BCNum, h: number): BCNum {
|
|
const b = f.n_len! + f.n_scale!;
|
|
const a = d.n_len! + d.n_scale!;
|
|
const g = f.n_scale! + d.n_scale!;
|
|
const e = libbcmath.MIN(
|
|
g,
|
|
libbcmath.MAX(h, libbcmath.MAX(f.n_scale!, d.n_scale!))
|
|
);
|
|
const c = libbcmath._bc_rec_mul(f, b, d, a, g);
|
|
c.n_sign = f.n_sign === d.n_sign ? libbcmath.PLUS : libbcmath.MINUS;
|
|
c.n_len = a + b + 1 - g;
|
|
c.n_scale = e;
|
|
libbcmath._bc_rm_leading_zeros(c);
|
|
if (libbcmath.bc_is_zero(c)) {
|
|
c.n_sign = libbcmath.PLUS;
|
|
}
|
|
return c;
|
|
},
|
|
new_sub_num: function (b: number, d: number, c: number[]): BCNum {
|
|
const a = new libbcmath.bc_num();
|
|
a.n_sign = libbcmath.PLUS;
|
|
a.n_len = b;
|
|
a.n_scale = d;
|
|
a.n_value = c;
|
|
return a;
|
|
},
|
|
_bc_simp_mul: function (
|
|
i: BCNum,
|
|
b: number,
|
|
h: BCNum,
|
|
m: number,
|
|
a: number
|
|
): BCNum {
|
|
const d = b + m + 1;
|
|
const j = libbcmath.bc_new_num(d, 0);
|
|
const n = b - 1;
|
|
const l = m - 1;
|
|
let f = d - 1;
|
|
let g = 0;
|
|
for (let e = 0; e < d - 1; e++) {
|
|
const k = n - libbcmath.MAX(0, e - m + 1);
|
|
const c = l - libbcmath.MIN(e, m - 1);
|
|
let kIdx = k;
|
|
let cIdx = c;
|
|
while (kIdx >= 0 && cIdx <= l) {
|
|
g += i.n_value![kIdx--] * h.n_value![cIdx++];
|
|
}
|
|
j.n_value![f--] = Math.floor(g % libbcmath.BASE);
|
|
g = Math.floor(g / libbcmath.BASE);
|
|
}
|
|
j.n_value![f] = g;
|
|
return j;
|
|
},
|
|
_bc_shift_addsub: function (
|
|
b: BCNum,
|
|
g: BCNum,
|
|
a: number,
|
|
d: boolean
|
|
): boolean {
|
|
let e = g.n_len!;
|
|
if (g.n_value![0] === 0) {
|
|
e--;
|
|
}
|
|
if (!(b.n_len! + b.n_scale! >= a + e)) {
|
|
throw new Error("len + scale < shift + count");
|
|
}
|
|
let c = b.n_len! + b.n_scale! - a - 1;
|
|
let h = g.n_len! - 1;
|
|
let f = 0;
|
|
if (d) {
|
|
while (e--) {
|
|
b.n_value![c] -= g.n_value![h--] + f;
|
|
if (b.n_value![c] < 0) {
|
|
f = 1;
|
|
b.n_value![c--] += libbcmath.BASE;
|
|
} else {
|
|
f = 0;
|
|
c--;
|
|
}
|
|
}
|
|
while (f) {
|
|
b.n_value![c] -= f;
|
|
if (b.n_value![c] < 0) {
|
|
b.n_value![c--] += libbcmath.BASE;
|
|
} else {
|
|
f = 0;
|
|
}
|
|
}
|
|
} else {
|
|
while (e--) {
|
|
b.n_value![c] += g.n_value![h--] + f;
|
|
if (b.n_value![c] > libbcmath.BASE - 1) {
|
|
f = 1;
|
|
b.n_value![c--] -= libbcmath.BASE;
|
|
} else {
|
|
f = 0;
|
|
c--;
|
|
}
|
|
}
|
|
while (f) {
|
|
b.n_value![c] += f;
|
|
if (b.n_value![c] > libbcmath.BASE - 1) {
|
|
b.n_value![c--] -= libbcmath.BASE;
|
|
} else {
|
|
f = 0;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
_bc_rec_mul: function (
|
|
m: BCNum,
|
|
i: number,
|
|
l: BCNum,
|
|
j: number,
|
|
c: number
|
|
): BCNum {
|
|
if (
|
|
i + j < libbcmath.MUL_BASE_DIGITS ||
|
|
i < libbcmath.MUL_SMALL_DIGITS ||
|
|
j < libbcmath.MUL_SMALL_DIGITS
|
|
) {
|
|
return libbcmath._bc_simp_mul(m, i, l, j, c);
|
|
}
|
|
const o = Math.floor((libbcmath.MAX(i, j) + 1) / 2);
|
|
let r: BCNum, s: BCNum;
|
|
if (i < o) {
|
|
r = libbcmath.bc_init_num();
|
|
s = libbcmath.new_sub_num(i, 0, m.n_value!);
|
|
} else {
|
|
r = libbcmath.new_sub_num(i - o, 0, m.n_value!);
|
|
s = libbcmath.new_sub_num(o, 0, m.n_value!.slice(i - o));
|
|
}
|
|
let g: BCNum, h: BCNum;
|
|
if (j < o) {
|
|
g = libbcmath.bc_init_num();
|
|
h = libbcmath.new_sub_num(j, 0, l.n_value!);
|
|
} else {
|
|
g = libbcmath.new_sub_num(j - o, 0, l.n_value!);
|
|
h = libbcmath.new_sub_num(o, 0, l.n_value!.slice(j - o));
|
|
}
|
|
libbcmath._bc_rm_leading_zeros(r);
|
|
libbcmath._bc_rm_leading_zeros(s);
|
|
const f = s.n_len!;
|
|
libbcmath._bc_rm_leading_zeros(g);
|
|
libbcmath._bc_rm_leading_zeros(h);
|
|
const p = h.n_len!;
|
|
const e = libbcmath.bc_is_zero(r) || libbcmath.bc_is_zero(g);
|
|
const y = libbcmath.bc_sub(r, s, 0);
|
|
const q = y.n_len!;
|
|
const x = libbcmath.bc_sub(h, g, 0);
|
|
const t = x.n_len!;
|
|
let d: BCNum;
|
|
if (e) {
|
|
d = libbcmath.bc_init_num();
|
|
} else {
|
|
d = libbcmath._bc_rec_mul(r, r.n_len!, g, g.n_len!, 0);
|
|
}
|
|
let b: BCNum;
|
|
if (libbcmath.bc_is_zero(y) || libbcmath.bc_is_zero(x)) {
|
|
b = libbcmath.bc_init_num();
|
|
} else {
|
|
b = libbcmath._bc_rec_mul(y, q, x, t, 0);
|
|
}
|
|
let a: BCNum;
|
|
if (libbcmath.bc_is_zero(s) || libbcmath.bc_is_zero(h)) {
|
|
a = libbcmath.bc_init_num();
|
|
} else {
|
|
a = libbcmath._bc_rec_mul(s, s.n_len!, h, h.n_len!, 0);
|
|
}
|
|
const w = i + j + 1;
|
|
const k = libbcmath.bc_new_num(w, 0);
|
|
if (!e) {
|
|
libbcmath._bc_shift_addsub(k, d, 2 * o, false);
|
|
libbcmath._bc_shift_addsub(k, d, o, false);
|
|
}
|
|
libbcmath._bc_shift_addsub(k, a, o, false);
|
|
libbcmath._bc_shift_addsub(k, a, 0, false);
|
|
libbcmath._bc_shift_addsub(k, b, o, y.n_sign !== x.n_sign);
|
|
return k;
|
|
},
|
|
bc_sub: function (e: BCNum, d: BCNum, c: number): BCNum {
|
|
let f: BCNum;
|
|
if (e.n_sign !== d.n_sign) {
|
|
f = libbcmath._bc_do_add(e, d, c);
|
|
f.n_sign = e.n_sign;
|
|
} else {
|
|
const b = libbcmath._bc_do_compare(e, d, false, false);
|
|
switch (b) {
|
|
case -1:
|
|
f = libbcmath._bc_do_sub(d, e, c);
|
|
f.n_sign =
|
|
d.n_sign === libbcmath.PLUS ? libbcmath.MINUS : libbcmath.PLUS;
|
|
break;
|
|
case 0:
|
|
const a = libbcmath.MAX(c, libbcmath.MAX(e.n_scale!, d.n_scale!));
|
|
f = libbcmath.bc_new_num(1, a);
|
|
libbcmath.memset(f.n_value!, 0, 0, a + 1);
|
|
break;
|
|
case 1:
|
|
f = libbcmath._bc_do_sub(e, d, c);
|
|
f.n_sign = e.n_sign;
|
|
break;
|
|
default:
|
|
f = libbcmath.bc_init_num();
|
|
}
|
|
}
|
|
return f;
|
|
},
|
|
};
|
|
|
|
libbcmath.MUL_SMALL_DIGITS = libbcmath.MUL_BASE_DIGITS / 4;
|
|
|
|
export function bcadd(b: BCNumValue, d: BCNumValue, f?: number): string {
|
|
if (typeof f === "undefined") {
|
|
f = libbcmath.scale;
|
|
}
|
|
f = f < 0 ? 0 : f;
|
|
let e = libbcmath.php_str2num(b.toString());
|
|
let c = libbcmath.php_str2num(d.toString());
|
|
if (e.n_scale! > c.n_scale!) {
|
|
c.setScale(e.n_scale!);
|
|
}
|
|
if (c.n_scale! > e.n_scale!) {
|
|
e.setScale(c.n_scale!);
|
|
}
|
|
let a = libbcmath.bc_add(e, c, f);
|
|
if (a.n_scale! > f) {
|
|
a.n_scale = f;
|
|
}
|
|
return a.toString();
|
|
}
|
|
|
|
export function bcsub(b: BCNumValue, d: BCNumValue, f?: number): string {
|
|
if (typeof f === "undefined") {
|
|
f = libbcmath.scale;
|
|
}
|
|
f = f < 0 ? 0 : f;
|
|
let e = libbcmath.php_str2num(b.toString());
|
|
let c = libbcmath.php_str2num(d.toString());
|
|
if (e.n_scale! > c.n_scale!) {
|
|
c.setScale(e.n_scale!);
|
|
}
|
|
if (c.n_scale! > e.n_scale!) {
|
|
e.setScale(c.n_scale!);
|
|
}
|
|
let a = libbcmath.bc_sub(e, c, f);
|
|
if (a.n_scale! > f) {
|
|
a.n_scale = f;
|
|
}
|
|
return a.toString();
|
|
}
|
|
|
|
export function bccomp(a: BCNumValue, c: BCNumValue, e?: number): number {
|
|
if (typeof e === "undefined") {
|
|
e = libbcmath.scale;
|
|
}
|
|
e = e < 0 ? 0 : e;
|
|
const d = libbcmath.bc_str2num(a.toString(), e);
|
|
const b = libbcmath.bc_str2num(c.toString(), e);
|
|
return libbcmath.bc_compare(d, b);
|
|
}
|
|
|
|
export function bcscale(a: number): boolean {
|
|
const parsedScale = parseInt(a.toString(), 10);
|
|
if (isNaN(parsedScale)) {
|
|
return false;
|
|
}
|
|
if (parsedScale < 0) {
|
|
return false;
|
|
}
|
|
libbcmath.scale = parsedScale;
|
|
return true;
|
|
}
|
|
|
|
export function bcdiv(b: BCNumValue, d: BCNumValue, f?: number): string {
|
|
if (typeof f === "undefined") {
|
|
f = libbcmath.scale;
|
|
}
|
|
f = f < 0 ? 0 : f;
|
|
let e = libbcmath.php_str2num(b.toString());
|
|
let c = libbcmath.php_str2num(d.toString());
|
|
if (e.n_scale! > c.n_scale!) {
|
|
c.setScale(e.n_scale!);
|
|
}
|
|
if (c.n_scale! > e.n_scale!) {
|
|
e.setScale(c.n_scale!);
|
|
}
|
|
const a = libbcmath.bc_divide(e, c, f);
|
|
if (a === -1) {
|
|
throw new Error("(BC) Division by zero");
|
|
}
|
|
if (a.n_scale! > f) {
|
|
a.n_scale = f;
|
|
}
|
|
return a.toString();
|
|
}
|
|
|
|
export function bcmul(b: BCNumValue, d: BCNumValue, f?: number): string {
|
|
if (typeof f === "undefined") {
|
|
f = libbcmath.scale;
|
|
}
|
|
f = f < 0 ? 0 : f;
|
|
let e = libbcmath.php_str2num(b.toString());
|
|
let c = libbcmath.php_str2num(d.toString());
|
|
if (e.n_scale! > c.n_scale!) {
|
|
c.setScale(e.n_scale!);
|
|
}
|
|
if (c.n_scale! > e.n_scale!) {
|
|
e.setScale(c.n_scale!);
|
|
}
|
|
let a = libbcmath.bc_multiply(e, c, f);
|
|
if (a.n_scale! > f) {
|
|
a.n_scale = f;
|
|
}
|
|
return a.toString();
|
|
}
|
|
|
|
export function bcround(d: BCNumValue, b: number): string {
|
|
let a = "0." + Array(b + 1).join("0") + "5";
|
|
if (d.toString().substring(0, 1) === "-") {
|
|
a = "-" + a;
|
|
}
|
|
const c = bcadd(d, a, b);
|
|
return c;
|
|
}
|