/* * QuickJS Javascript Calculator * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ "use strict"; "use math"; var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix; (function(global) { /* the types index are used to dispatch the operator functions */ var OT_INT = 0; var OT_FRACTION = 10; var OT_FLOAT64 = 19; var OT_FLOAT = 20; var OT_COMPLEX = 30; var OT_MOD = 40; var OT_POLY = 50; var OT_POLYMOD = 55; var OT_RFUNC = 60; var OT_SERIES = 70; var OT_ARRAY = 80; global.Integer = global.BigInt; global.algebraicMode = true; /* add non enumerable properties */ function add_props(obj, props) { var i, val, prop, tab, desc, prop1; tab = Reflect.ownKeys(props); for(i = 0; i < tab.length; i++) { prop = tab[i]; desc = Object.getOwnPropertyDescriptor(props, prop); desc.enumerable = false; if ("value" in desc) { if (typeof desc.value !== "function") { desc.writable = false; desc.configurable = false; } } else { /* getter/setter */ desc.configurable = false; } Object.defineProperty(obj, prop, desc); if (obj !== Integer) { /* by default also add the non math operators */ switch(prop) { case Symbol.operatorMathDiv: prop1 = Symbol.operatorDiv; break; case Symbol.operatorMathMod: prop1 = Symbol.operatorMod; break; case Symbol.operatorMathPow: prop1 = Symbol.operatorPow; break; default: prop1 = null; break; } if (prop1) Object.defineProperty(obj, prop1, desc); } } } /* Integer */ function generic_pow(a, b) { var r, is_neg, i; if (!Integer.isInteger(b)) { return exp(log(a) * b); } if (Array.isArray(a) && !(a instanceof Polynomial || a instanceof Series)) { r = idn(Matrix.check_square(a)); } else { r = 1; } if (b == 0) return r; is_neg = false; if (b < 0) { is_neg = true; b = -b; } r = a; for(i = Integer.floorLog2(b) - 1; i >= 0; i--) { r *= r; if ((b >> i) & 1) r *= a; } if (is_neg) { if (typeof r.inverse != "function") throw "negative powers are not supported for this type"; r = r.inverse(); } return r; } var small_primes = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499 ]; function miller_rabin_test(n, t) { var d, r, s, i, j, a; d = n - 1; s = 0; while (d & 1) { d >>= 1; s++; } t = Math.min(t, small_primes.length); loop: for(j = 0; j < t; j++) { a = small_primes[j]; r = Integer.pmod(a, d, n); if (r == 1 || r == (n - 1)) continue; for(i = 1; i < s; i++) { r = (r * r) % n; if (r == 1) return false; if (r == (n - 1)) continue loop; } return false; /* n is composite */ } return true; /* n is probably prime with probability (1-0.5^t) */ } function fact_rec(a, b) { /* assumes a <= b */ var i, r; if ((b - a) <= 5) { r = a; for(i = a + 1; i <= b; i++) r *= i; return r; } else { /* to avoid a quadratic running time it is better to multiply numbers of similar size */ i = (a + b) >> 1; return fact_rec(a, i) * fact_rec(i + 1, b); } } add_props(Integer, { isInteger(a) { return typeof a === "bigint"; }, [Symbol.operatorOrder]: OT_INT, [Symbol.operatorMathDiv](a, b) { if (algebraicMode) { return Fraction.toFraction(a, b); } else { return Float(a) / Float(b); } }, [Symbol.operatorMathPow](a, b) { if (algebraicMode) { return generic_pow(a, b); } else { return Float(a) ** Float(b); } }, gcd(a, b) { var r; while (b != 0) { r = a % b; a = b; b = r; } return a; }, fact(n) { return n <= 0 ? 1 : fact_rec(1, n); }, /* binomial coefficient */ comb(n, k) { if (k < 0 || k > n) return 0; if (k > n - k) k = n - k; if (k == 0) return 1; return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k)); }, /* inverse of x modulo y */ invmod(x, y) { var q, u, v, a, c, t; u = x; v = y; c = 1; a = 0; while (u != 0) { t = Integer.fdivrem(v, u); q = t[0]; v = u; u = t[1]; t = c; c = a - q * c; a = t; } /* v = gcd(x, y) */ if (v != 1) throw RangeError("not invertible"); return a % y; }, /* return a ^ b modulo m */ pmod(a, b, m) { var r; if (b == 0) return 1; if (b < 0) { a = Integer.invmod(a, m); b = -b; } r = 1; for(;;) { if (b & 1) { r = (r * a) % m; } b >>= 1; if (b == 0) break; a = (a * a) % m; } return r; }, /* return true if n is prime (or probably prime with probability 1-0.5^t) */ isPrime(n, t) { var i, d, n1; if (!Integer.isInteger(n)) throw TypeError("invalid type"); if (n <= 1) return false; n1 = small_primes.length; /* XXX: need Integer.sqrt() */ for(i = 0; i < n1; i++) { d = small_primes[i]; if (d == n) return true; if (d > n) return false; if ((n % d) == 0) return false; } if (n < d * d) return true; if (typeof t == "undefined") t = 64; return miller_rabin_test(n, t); }, nextPrime(n) { if (!Integer.isInteger(n)) throw TypeError("invalid type"); if (n < 1) n = 1; for(;;) { n++; if (Integer.isPrime(n)) return n; } }, factor(n) { var r, d; if (!Integer.isInteger(n)) throw TypeError("invalid type"); r = []; if (abs(n) <= 1) { r.push(n); return r; } if (n < 0) { r.push(-1); n = -n; } while ((n % 2) == 0) { n >>= 1; r.push(2); } d = 3; while (n != 1) { if (Integer.isPrime(n)) { r.push(n); break; } /* we are sure there is at least one divisor, so one test */ for(;;) { if ((n % d) == 0) break; d += 2; } for(;;) { r.push(d); n = Integer.tdiv(n, d); if ((n % d) != 0) break; } } return r; }, }); add_props(Integer.prototype, { inverse() { return 1 / this; }, norm2() { return this * this; }, abs() { return Math.abs(this); }, conj() { return this; }, arg() { if (this >= 0) return 0; else return Float.PI; }, exp() { if (this == 0) return 1; else return Float.exp(this); }, log() { if (this == 1) return 0; else return Float(this).log(); }, }); /* Fraction */ Fraction = function Fraction(a, b) { var d, r, obj; if (new.target) throw TypeError("not a constructor"); if (a instanceof Fraction) return a; if (!Integer.isInteger(a)) throw TypeError("integer expected"); if (typeof b === "undefined") { b = 1; } else { if (!Integer.isInteger(b)) throw TypeError("integer expected"); if (b == 0) throw RangeError("division by zero"); d = Integer.gcd(a, b); if (d != 1) { a = Integer.tdiv(a, d); b = Integer.tdiv(b, d); } /* the fractions are normalized with den > 0 */ if (b < 0) { a = -a; b = -b; } } obj = Object.create(Fraction.prototype); obj.num = a; obj.den = b; return obj; } add_props(Fraction, { [Symbol.operatorOrder]: OT_FRACTION, /* (internal use) simplify 'a' to an integer when possible */ toFraction(a, b) { var r = Fraction(a, b); if (algebraicMode && r.den == 1) return r.num; else return r; }, [Symbol.operatorAdd](a, b) { a = Fraction(a); b = Fraction(b); return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); }, [Symbol.operatorSub](a, b) { a = Fraction(a); b = Fraction(b); return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); }, [Symbol.operatorMul](a, b) { a = Fraction(a); b = Fraction(b); return Fraction.toFraction(a.num * b.num, a.den * b.den); }, [Symbol.operatorMathDiv](a, b) { a = Fraction(a); b = Fraction(b); return Fraction.toFraction(a.num * b.den, a.den * b.num); }, [Symbol.operatorMathMod](a, b) { var a1 = Fraction(a); var b1 = Fraction(b); return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorCmpEQ](a, b) { a = Fraction(a); b = Fraction(b); /* we assume the fractions are normalized */ return (a.num == b.num && a.den == b.den); }, [Symbol.operatorCmpLT](a, b) { a = Fraction(a); b = Fraction(b); return (a.num * b.den < b.num * a.den); }, [Symbol.operatorCmpLE](a, b) { a = Fraction(a); b = Fraction(b); return (a.num * b.den <= b.num * a.den); }, }); add_props(Fraction.prototype, { [Symbol.toPrimitive](hint) { if (hint === "integer") { return Integer.tdiv(this.num, this.den); } else if (hint === "string") { return this.toString(); } else { return Float(this.num) / this.den; } }, [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { return Fraction(-this.num, this.den); }, inverse() { return Fraction(this.den, this.num); }, toString() { return this.num + "/" + this.den; }, norm2() { return this * this; }, abs() { if (this.num < 0) return this[Symbol.operatorNeg](); else return this; }, conj() { return this; }, arg() { if (this.num >= 0) return 0; else return Float.PI; }, exp() { return Float.exp(Float(this)); }, log() { return Float(this).log(); }, }); /* Number (Float64) */ add_props(Number, { [Symbol.operatorOrder]: OT_FLOAT64, /* operators are needed for fractions */ [Symbol.operatorAdd](a, b) { return Number(a) + Number(b); }, [Symbol.operatorSub](a, b) { return Number(a) - Number(b); }, [Symbol.operatorMul](a, b) { return Number(a) * Number(b); }, [Symbol.operatorMathDiv](a, b) { return Number(a) / Number(b); }, [Symbol.operatorMathPow](a, b) { return Number(a) ** Number(b); }, }); add_props(Number.prototype, { inverse() { return 1.0 / this; }, norm2() { return this * this; }, abs() { return Math.abs(this); }, conj() { return this; }, arg() { if (this >= 0) return 0; else return Float.PI; }, exp() { return Float.exp(this); }, log() { if (this < 0) { return Complex(this).log(); } else { return Float.log(this); } }, }); /* Float */ global.Float = global.BigFloat; var const_tab = []; /* we cache the constants for small precisions */ function get_const(n) { var t, c, p; t = const_tab[n]; p = BigFloatEnv.prec; if (t && t.prec == p) { return t.val; } else { switch(n) { case 0: c = Float.exp(1); break; case 1: c = Float.log(10); break; // case 2: c = Float.log(2); break; case 3: c = 1/Float.log(2); break; case 4: c = 1/Float.log(10); break; // case 5: c = Float.atan(1) * 4; break; case 6: c = Float.sqrt(0.5); break; case 7: c = Float.sqrt(2); break; } if (p <= 1024) { const_tab[n] = { prec: p, val: c }; } return c; } } add_props(Float, { isFloat(a) { return typeof a === "number" || typeof a === "bigfloat"; }, bestappr(u, b) { var num1, num0, den1, den0, u, num, den, n; if (typeof b === "undefined") throw TypeError("second argument expected"); num1 = 1; num0 = 0; den1 = 0; den0 = 1; for(;;) { n = Integer(Float.floor(u)); num = n * num1 + num0; den = n * den1 + den0; if (den > b) break; u = 1.0 / (u - n); num0 = num1; num1 = num; den0 = den1; den1 = den; } return Fraction(num1, den1); }, /* similar constants as Math.x */ get E() { return get_const(0); }, get LN10() { return get_const(1); }, // get LN2() { return get_const(2); }, get LOG2E() { return get_const(3); }, get LOG10E() { return get_const(4); }, // get PI() { return get_const(5); }, get SQRT1_2() { return get_const(6); }, get SQRT2() { return get_const(7); }, }); add_props(Float, { [Symbol.operatorOrder]: OT_FLOAT, /* operators are needed for fractions */ [Symbol.operatorAdd](a, b) { return Float(a) + Float(b); }, [Symbol.operatorSub](a, b) { return Float(a) - Float(b); }, [Symbol.operatorMul](a, b) { return Float(a) * Float(b); }, [Symbol.operatorMathDiv](a, b) { return Float(a) / Float(b); }, [Symbol.operatorMathPow](a, b) { return Float(a) ** Float(b); }, }); add_props(Float.prototype, { inverse() { return 1.0 / this; }, norm2() { return this * this; }, abs() { return Math.abs(this); }, conj() { return this; }, arg() { if (this >= 0) return 0; else return Float.PI; }, exp() { return Float.exp(this); }, log() { if (this < 0) { return Complex(this).log(); } else { return Float.log(this); } }, }); /* Complex */ Complex = function Complex(re, im) { var obj; if (new.target) throw TypeError("not a constructor"); if (re instanceof Complex) return re; if (typeof im === "undefined") { im = 0; } obj = Object.create(Complex.prototype); obj.re = re; obj.im = im; return obj; } add_props(Complex, { [Symbol.operatorOrder]: OT_COMPLEX, /* simplify to real number when possible */ toComplex(re, im) { if (algebraicMode && im == 0) return re; else return Complex(re, im); }, [Symbol.operatorAdd](a, b) { a = Complex(a); b = Complex(b); return Complex.toComplex(a.re + b.re, a.im + b.im); }, [Symbol.operatorSub](a, b) { a = Complex(a); b = Complex(b); return Complex.toComplex(a.re - b.re, a.im - b.im); }, [Symbol.operatorMul](a, b) { a = Complex(a); b = Complex(b); return Complex.toComplex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re); }, [Symbol.operatorMathDiv](a, b) { a = Complex(a); b = Complex(b); return a * b.inverse(); }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorCmpEQ](a, b) { a = Complex(a); b = Complex(b); return a.re == b.re && a.im == b.im; } }); add_props(Complex.prototype, { [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { return Complex(-this.re, -this.im); }, inverse() { var c = this.norm2(); return Complex(this.re / c, -this.im / c); }, toString() { var v, s = "", a = this; if (a.re != 0) s += a.re.toString(); if (a.im == 1) { if (s != "") s += "+"; s += "I"; } else if (a.im == -1) { s += "-I"; } else { v = a.im.toString(); if (v[0] != "-" && s != "") s += "+"; s += v + "*I"; } return s; }, norm2() { return this.re * this.re + this.im * this.im; }, abs() { return Float.sqrt(norm2(this)); }, conj() { return Complex(this.re, -this.im); }, arg() { return Float.atan2(this.im, this.re); }, exp() { var arg = this.im, r = this.re.exp(); return Complex(r * cos(arg), r * sin(arg)); }, log() { return Complex(abs(this).log(), atan2(this.im, this.re)); }, }); /* Mod */ Mod = function Mod(a, m) { var obj, t; if (new.target) throw TypeError("not a constructor"); obj = Object.create(Mod.prototype); if (Integer.isInteger(m)) { if (m <= 0) throw RangeError("the modulo cannot be <= 0"); if (Integer.isInteger(a)) { a %= m; } else if (a instanceof Fraction) { return Mod(a.num, m) / a.den; } else { throw TypeError("invalid types"); } } else { throw TypeError("invalid types"); } obj.res = a; obj.mod = m; return obj; }; add_props(Mod.prototype, { [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { return Mod(-this.res, this.mod); }, inverse() { var a = this, m = a.mod; if (Integer.isInteger(m)) { return Mod(Integer.invmod(a.res, m), m); } else { throw TypeError("unsupported type"); } }, toString() { return "Mod(" + this.res + "," + this.mod + ")"; }, }); add_props(Mod, { [Symbol.operatorOrder]: OT_MOD, [Symbol.operatorAdd](a, b) { if (!(a instanceof Mod)) { return Mod(a + b.res, b.mod); } else if (!(b instanceof Mod)) { return Mod(a.res + b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return Mod(a.res + b.res, a.mod); } }, [Symbol.operatorSub](a, b) { if (!(a instanceof Mod)) { return Mod(a - b.res, b.mod); } else if (!(b instanceof Mod)) { return Mod(a.res - b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return Mod(a.res - b.res, a.mod); } }, [Symbol.operatorMul](a, b) { if (!(a instanceof Mod)) { return Mod(a * b.res, b.mod); } else if (!(b instanceof Mod)) { return Mod(a.res * b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return Mod(a.res * b.res, a.mod); } }, [Symbol.operatorMathDiv](a, b) { if (!(b instanceof Mod)) b = Mod(b, a.mod); return Mod[Symbol.operatorMul](a, b.inverse()); }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorCmpEQ](a, b) { if (!(a instanceof Mod) || !(b instanceof Mod)) return false; return (a.mod == b.mod && a.res == b.res); } }); /* Polynomial */ Polynomial = function Polynomial(a) { if (new.target) throw TypeError("not a constructor"); if (a instanceof Polynomial) { return a; } else if (Array.isArray(a)) { if (a.length == 0) a = [ 0 ]; Object.setPrototypeOf(a, Polynomial.prototype); return a.trim(); } else if (a.constructor[Symbol.operatorOrder] <= OT_MOD) { a = [a]; Object.setPrototypeOf(a, Polynomial.prototype); return a; } else { throw TypeError("invalid type"); } } function number_need_paren(c) { return !(Integer.isInteger(c) || Float.isFloat(c) || c instanceof Fraction || (c instanceof Complex && c.re == 0)); } /* string for c*X^i */ function monomial_toString(c, i) { var str1; if (i == 0) { str1 = c.toString(); } else { if (c == 1) { str1 = ""; } else if (c == -1) { str1 = "-"; } else { if (number_need_paren(c)) { str1 = "(" + c + ")"; } else { str1 = String(c); } str1 += "*"; } str1 += "X"; if (i != 1) { str1 += "^" + i; } } return str1; } /* find one complex root of 'p' starting from z at precision eps using at most max_it iterations. Return null if could not find root. */ function poly_root_laguerre1(p, z, max_it) { var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl; d = p.deg(); if (d == 1) { /* monomial case */ return -p[0] / p[1]; } /* trivial zero */ if (p[0] == 0) return 0.0; p1 = p.deriv(); p2 = p1.deriv(); el = 0.0; zl = 0.0; for(i = 0; i < max_it; i++) { z0 = p.apply(z); if (z0 == 0) return z; /* simple exit case */ /* Ward stopping criteria */ e = abs(z - zl); // print("e", i, e); if (i >= 2 && e >= el) { if (abs(zl) < 1e-4) { if (e < 1e-7) return zl; } else { if (e < abs(zl) * 1e-3) return zl; } } el = e; zl = z; z1 = p1.apply(z); z2 = p2.apply(z); t0 = (d - 1) * z1; t0 = t0 * t0; t1 = d * (d - 1) * z0 * z2; t0 = sqrt(t0 - t1); d1 = z1 + t0; d2 = z1 - t0; if (norm2(d2) > norm2(d1)) d1 = d2; if (d1 == 0) return null; z = z - d * z0 / d1; } return null; } function poly_roots(p) { var d, i, roots, j, z, eps; var start_points = [ 0.1, -1.4, 1.7 ]; if (!(p instanceof Polynomial)) throw TypeError("polynomial expected"); d = p.deg(); if (d <= 0) return []; eps = 2.0 ^ (-BigFloatEnv.prec); roots = []; for(i = 0; i < d; i++) { /* XXX: should select another start point if error */ for(j = 0; j < 3; j++) { z = poly_root_laguerre1(p, start_points[j], 100); if (z !== null) break; } if (j == 3) throw RangeError("error in root finding algorithm"); roots[i] = z; p = Polynomial.divrem(p, X - z)[0]; } return roots; } add_props(Polynomial.prototype, { trim() { var a = this, i; i = a.length; while (i > 1 && a[i - 1] == 0) i--; a.length = i; return a; }, [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { var r, i, n, a; a = this; n = a.length; r = []; for(i = 0; i < n; i++) r[i] = -a[i]; return Polynomial(r); }, conj() { var r, i, n, a; a = this; n = a.length; r = []; for(i = 0; i < n; i++) r[i] = a[i].conj(); return Polynomial(r); }, inverse() { return RationalFunction(Polynomial([1]), this); }, toString() { var i, str, str1, c, a = this; if (a.length == 1) { return a[0].toString(); } str=""; for(i = a.length - 1; i >= 0; i--) { c = a[i]; if (c == 0 || (c instanceof Mod) && c.res == 0) continue; str1 = monomial_toString(c, i); if (str1[0] != "-") { if (str != "") str += "+"; } str += str1; } return str; }, deg() { if (this.length == 1 && this[0] == 0) return -Infinity; else return this.length - 1; }, apply(b) { var i, n, r, a = this; n = a.length - 1; r = a[n]; while (n > 0) { n--; r = r * b + a[n]; } return r; }, deriv() { var a = this, n, r, i; n = a.length; if (n == 1) { return Polynomial(0); } else { r = []; for(i = 1; i < n; i++) { r[i - 1] = i * a[i]; } return Polynomial(r); } }, integ() { var a = this, n, r, i; n = a.length; r = [0]; for(i = 0; i < n; i++) { r[i + 1] = a[i] / (i + 1); } return Polynomial(r); }, norm2() { var a = this, n, r, i; n = a.length; r = 0; for(i = 0; i < n; i++) { r += a[i].norm2(); } return r; }, }); add_props(Polynomial, { [Symbol.operatorOrder]: OT_POLY, [Symbol.operatorAdd](a, b) { var tmp, r, i, n1, n2; a = Polynomial(a); b = Polynomial(b); if (a.length < b.length) { tmp = a; a = b; b = tmp; } n1 = b.length; n2 = a.length; r = []; for(i = 0; i < n1; i++) r[i] = a[i] + b[i]; for(i = n1; i < n2; i++) r[i] = a[i]; return Polynomial(r); }, [Symbol.operatorSub](a, b) { return Polynomial[Symbol.operatorAdd](a, -b); }, [Symbol.operatorMul](a, b) { var i, j, n1, n2, n, r; a = Polynomial(a); b = Polynomial(b); n1 = a.length; n2 = b.length; n = n1 + n2 - 1; r = []; for(i = 0; i < n; i++) r[i] = 0; for(i = 0; i < n1; i++) { for(j = 0; j < n2; j++) { r[i + j] += a[i] * b[j]; } } return Polynomial(r); }, [Symbol.operatorMathDiv](a, b) { if (b.constructor[Symbol.operatorOrder] <= OT_COMPLEX) return a * (1 / b); else return RationalFunction(Polynomial(a), Polynomial(b)); }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorMathMod](a, b) { return Polynomial.divrem(a, b)[1]; }, [Symbol.operatorCmpEQ](a, b) { var n, i; if (!(a instanceof Polynomial) || !(b instanceof Polynomial)) return false; n = a.length; if (n != b.length) return false; for(i = 0; i < n; i++) { if (a[i] != b[i]) return false; } return true; }, divrem(a, b) { var n1, n2, i, j, q, r, n, c; if (b.deg() < 0) throw RangeError("division by zero"); n1 = a.length; n2 = b.length; if (n1 < n2) return [Polynomial([0]), a]; r = Array.prototype.dup.call(a); q = []; n2--; n = n1 - n2; for(i = 0; i < n; i++) q[i] = 0; for(i = n - 1; i >= 0; i--) { c = r[i + n2]; if (c != 0) { c = c / b[n2]; r[i + n2] = 0; for(j = 0; j < n2; j++) { r[i + j] -= b[j] * c; } q[i] = c; } } return [Polynomial(q), Polynomial(r)]; }, gcd(a, b) { var t; while (b.deg() >= 0) { t = Polynomial.divrem(a, b); a = b; b = t[1]; } /* convert to monic form */ return a / a[a.length - 1]; }, invmod(x, y) { var q, u, v, a, c, t; u = x; v = y; c = Polynomial([1]); a = Polynomial([0]); while (u.deg() >= 0) { t = Polynomial.divrem(v, u); q = t[0]; v = u; u = t[1]; t = c; c = a - q * c; a = t; } /* v = gcd(x, y) */ if (v.deg() > 0) throw RangeError("not invertible"); return Polynomial.divrem(a, y)[1]; }, roots(p) { return poly_roots(p); } }); /* Polynomial Modulo Q */ PolyMod = function PolyMod(a, m) { var obj, t; if (new.target) throw TypeError("not a constructor"); obj = Object.create(PolyMod.prototype); if (m instanceof Polynomial) { if (m.deg() <= 0) throw RangeError("the modulo cannot have a degree <= 0"); if (a instanceof RationalFunction) { return PolyMod(a.num, m) / a.den; } else { a = Polynomial(a); t = Polynomial.divrem(a, m); a = t[1]; } } else { throw TypeError("invalid types"); } obj.res = a; obj.mod = m; return obj; }; add_props(PolyMod.prototype, { [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { return PolyMod(-this.res, this.mod); }, inverse() { var a = this, m = a.mod; if (m instanceof Polynomial) { return PolyMod(Polynomial.invmod(a.res, m), m); } else { throw TypeError("unsupported type"); } }, toString() { return "PolyMod(" + this.res + "," + this.mod + ")"; }, }); add_props(PolyMod, { [Symbol.operatorOrder]: OT_POLYMOD, [Symbol.operatorAdd](a, b) { if (!(a instanceof PolyMod)) { return PolyMod(a + b.res, b.mod); } else if (!(b instanceof PolyMod)) { return PolyMod(a.res + b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return PolyMod(a.res + b.res, a.mod); } }, [Symbol.operatorSub](a, b) { if (!(a instanceof PolyMod)) { return PolyMod(a - b.res, b.mod); } else if (!(b instanceof PolyMod)) { return PolyMod(a.res - b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return PolyMod(a.res - b.res, a.mod); } }, [Symbol.operatorMul](a, b) { if (!(a instanceof PolyMod)) { return PolyMod(a * b.res, b.mod); } else if (!(b instanceof PolyMod)) { return PolyMod(a.res * b, a.mod); } else { if (a.mod != b.mod) throw TypeError("different modulo for binary operator"); return PolyMod(a.res * b.res, a.mod); } }, [Symbol.operatorMathDiv](a, b) { if (!(b instanceof PolyMod)) b = PolyMod(b, a.mod); return PolyMod[Symbol.operatorMul](a, b.inverse()); }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorCmpEQ](a, b) { if (!(a instanceof PolyMod) || !(b instanceof PolyMod)) return false; return (a.mod == b.mod && a.res == b.res); } }); /* Rational function */ RationalFunction = function RationalFunction(a, b) { var t, r, d, obj; if (new.target) throw TypeError("not a constructor"); if (!(a instanceof Polynomial) || !(b instanceof Polynomial)) throw TypeError("polynomial expected"); t = Polynomial.divrem(a, b); r = t[1]; if (r.deg() < 0) return t[0]; /* no need for a fraction */ d = Polynomial.gcd(b, r); if (d.deg() > 0) { a = Polynomial.divrem(a, d)[0]; b = Polynomial.divrem(b, d)[0]; } obj = Object.create(RationalFunction.prototype); obj.num = a; obj.den = b; return obj; } add_props(RationalFunction.prototype, { [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { return RationalFunction(-this.num, this.den); }, inverse() { return RationalFunction(this.den, this.num); }, conj() { return RationalFunction(this.num.conj(), this.den.conj()); }, toString() { var str; if (this.num.deg() <= 0 && !number_need_paren(this.num[0])) str = this.num.toString(); else str = "(" + this.num.toString() + ")"; str += "/(" + this.den.toString() + ")" return str; }, apply(b) { return this.num.apply(b) / this.den.apply(b); }, deriv() { var n = this.num, d = this.den; return RationalFunction(n.deriv() * d - n * d.deriv(), d * d); }, }); add_props(RationalFunction, { [Symbol.operatorOrder]: OT_RFUNC, /* This function always return a RationalFunction object even if it could simplified to a polynomial, so it is not equivalent to RationalFunction(a) */ toRationalFunction(a) { var obj; if (a instanceof RationalFunction) { return a; } else { obj = Object.create(RationalFunction.prototype); obj.num = Polynomial(a); obj.den = Polynomial(1); return obj; } }, [Symbol.operatorAdd](a, b) { a = RationalFunction.toRationalFunction(a); b = RationalFunction.toRationalFunction(b); return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); }, [Symbol.operatorSub](a, b) { a = RationalFunction.toRationalFunction(a); b = RationalFunction.toRationalFunction(b); return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); }, [Symbol.operatorMul](a, b) { a = RationalFunction.toRationalFunction(a); b = RationalFunction.toRationalFunction(b); return RationalFunction(a.num * b.num, a.den * b.den); }, [Symbol.operatorMathDiv](a, b) { a = RationalFunction.toRationalFunction(a); b = RationalFunction.toRationalFunction(b); return RationalFunction(a.num * b.den, a.den * b.num); }, [Symbol.operatorMathPow]: generic_pow, [Symbol.operatorCmpEQ](a, b) { a = RationalFunction.toRationalFunction(a); b = RationalFunction.toRationalFunction(b); /* we assume the fractions are normalized */ return (a.num == b.num && a.den == b.den); }, }); /* Power series */ /* 'a' is an array */ function get_emin(a) { var i, n; n = a.length; for(i = 0; i < n; i++) { if (a[i] != 0) return i; } return n; }; /* n is the maximum number of terms if 'a' is not a serie */ Series = function Series(a, n) { var emin, r, i; if (a instanceof Series) { return a; } else if (a.constructor[Symbol.operatorOrder] <= OT_POLY) { if (n <= 0) { /* XXX: should still use the polynomial degree */ return Series.zero(0, 0); } else { a = Polynomial(a); emin = get_emin(a); r = Series.zero(n, emin); n = Math.min(a.length - emin, n); for(i = 0; i < n; i++) r[i] = a[i + emin]; return r; } } else if (a instanceof RationalFunction) { return Series(a.num, n) / a.den; } else { throw TypeError("invalid type"); } }; add_props(Series.prototype, { [Symbol.operatorPlus]() { return this; }, [Symbol.operatorNeg]() { var obj, n, i; n = this.length; obj = Series.zero(this.length, this.emin); for(i = 0; i < n; i++) { obj[i] = -this[i]; } return obj; }, conj() { var obj, n, i; n = this.length; obj = Series.zero(this.length, this.emin); for(i = 0; i < n; i++) { obj[i] = this[i].conj(); } return obj; }, inverse() { var r, n, i, j, sum, v1 = this; n = v1.length; if (n == 0) throw RangeError("division by zero"); r = Series.zero(n, -v1.emin); r[0] = 1 / v1[0]; for(i = 1; i < n; i++) { sum = 0; for(j = 1; j <= i; j++) { sum += v1[j] * r[i - j]; } r[i] = -sum * r[0]; } return r; }, /* remove leading zero terms */ trim() { var i, j, n, r, v1 = this; n = v1.length; i = 0; while (i < n && v1[i] == 0) i++; if (i == 0) return v1; for(j = i; j < n; j++) v1[j - i] = v1[j]; v1.length = n - i; v1.__proto__.emin += i; return v1; }, toString() { var i, j, str, str1, c, a = this, emin, n; str=""; emin = this.emin; n = this.length; for(j = 0; j < n; j++) { i = j + emin; c = a[j]; if (c != 0) { str1 = monomial_toString(c, i); if (str1[0] != "-") { if (str != "") str += "+"; } str += str1; } } if (str != "") str += "+"; str += "O(" + monomial_toString(1, n + emin) + ")"; return str; }, apply(b) { var i, n, r, a = this; n = a.length; if (n == 0) return 0; r = a[--n]; while (n > 0) { n--; r = r * b + a[n]; } if (a.emin != 0) r *= b ^ a.emin; return r; }, deriv() { var a = this, n = a.length, emin = a.emin, r, i, j; if (n == 0 && emin == 0) { return Series.zero(0, 0); } else { r = Series.zero(n, emin - 1); for(i = 0; i < n; i++) { j = emin + i; if (j == 0) r[i] = 0; else r[i] = j * a[i]; } return r.trim(); } }, integ() { var a = this, n = a.length, emin = a.emin, i, j, r; r = Series.zero(n, emin + 1); for(i = 0; i < n; i++) { j = emin + i; if (j == -1) { if (a[i] != 0) throw RangError("cannot represent integ(1/X)"); } else { r[i] = a[i] / (j + 1); } } return r.trim(); }, exp() { var c, i, r, n, a = this; n = a.emin; if (n < 0) throw RangeError("negative exponent in exp"); if (n > 0 || a[0] == 0) { c = 1; } else { c = global.exp(a[0]); a -= a[0]; } n += a.length; r = Series.zero(n, 0); for(i = 0; i < n; i++) { r[i] = c / fact(i); } return r.apply(a); }, log() { var a = this, r; if (a.emin != 0) throw Range("log argument must have a non zero constant term"); r = integ(deriv(a) / a); /* add the constant term */ r += global.log(a[0]); return r; }, }); add_props(Series, { [Symbol.operatorOrder]: OT_SERIES, /* new series of length n and first exponent emin */ zero(n, emin) { var r, i, obj; r = []; for(i = 0; i < n; i++) r[i] = 0; /* we return an array and store emin in its prototype */ obj = Object.create(Series.prototype); obj.emin = emin; Object.setPrototypeOf(r, obj); return r; }, [Symbol.operatorAdd](v1, v2) { var tmp, d, emin, n, r, i, j, v2_emin, c1, c2; if (!(v1 instanceof Series)) { tmp = v1; v1 = v2; v2 = tmp; } d = v1.emin + v1.length; if (v2.constructor[Symbol.operatorOrder] <= OT_POLY) { v2 = Polynomial(v2); if (d <= 0) return v1; v2_emin = 0; } else if (v2 instanceof RationalFunction) { /* compute the emin of the rational fonction */ i = get_emin(v2.num) - get_emin(v2.den); if (d <= i) return v1; /* compute the serie with the required terms */ v2 = Series(v2, d - i); v2_emin = v2.emin; } else { v2_emin = v2.emin; d = Math.min(d, v2_emin + v2.length); } emin = Math.min(v1.emin, v2_emin); n = d - emin; r = Series.zero(n, emin); /* XXX: slow */ for(i = emin; i < d; i++) { j = i - v1.emin; if (j >= 0 && j < v1.length) c1 = v1[j]; else c1 = 0; j = i - v2_emin; if (j >= 0 && j < v2.length) c2 = v2[j]; else c2 = 0; r[i - emin] = c1 + c2; } return r.trim(); }, [Symbol.operatorSub](a, b) { return Series[Symbol.operatorAdd](a, -b); }, [Symbol.operatorMul](v1, v2) { var n, i, j, r, n, emin, n1, n2, k; if (!(v1 instanceof Series)) v1 = Series(v1, v2.length); else if (!(v2 instanceof Series)) v2 = Series(v2, v1.length); emin = v1.emin + v2.emin; n = Math.min(v1.length, v2.length); n1 = v1.length; n2 = v2.length; r = Series.zero(n, emin); for(i = 0; i < n1; i++) { k = Math.min(n2, n - i); for(j = 0; j < k; j++) { r[i + j] += v1[i] * v2[j]; } } return r.trim(); }, [Symbol.operatorMathDiv](v1, v2) { if (!(v2 instanceof Series)) v2 = Series(v2, v1.length); return Series[Symbol.operatorMul](v1, v2.inverse()); }, [Symbol.operatorMathPow](a, b) { if (Integer.isInteger(b)) { return generic_pow(a, b); } else { if (!(a instanceof Series)) a = Series(a, b.length); return exp(log(a) * b); } }, [Symbol.operatorCmpEQ](a, b) { var n, i; if (!(a instanceof Series) || !(b instanceof Series)) return false; if (a.emin != b.emin) return false; n = a.length; if (n != b.length) return false; for(i = 0; i < n; i++) { if (a[i] != b[i]) return false; } return true; }, O(a) { function ErrorO() { return TypeError("invalid O() argument"); } var n; if (a.constructor[Symbol.operatorOrder] <= OT_POLY) { a = Polynomial(a); n = a.deg(); if (n < 0) throw ErrorO(); } else if (a instanceof RationalFunction) { if (a.num.deg() != 0) throw ErrorO(); n = a.den.deg(); if (n < 0) throw ErrorO(); n = -n; } else throw ErrorO(); return Series.zero(0, n); }, }); /* Array (Matrix) */ Matrix = function Matrix(h, w) { var i, j, r, rl; if (typeof w === "undefined") w = h; r = []; for(i = 0; i < h; i++) { rl = []; for(j = 0; j < w; j++) rl[j] = 0; r[i] = rl; } return r; }; add_props(Matrix, { idn(n) { var r, i; r = Matrix(n, n); for(i = 0; i < n; i++) r[i][i] = 1; return r; }, diag(a) { var r, i, n; n = a.length; r = Matrix(n, n); for(i = 0; i < n; i++) r[i][i] = a[i]; return r; }, hilbert(n) { var i, j, r; r = Matrix(n); for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { r[i][j] = 1 / (1 + i + j); } } return r; }, trans(a) { var h, w, r, i, j; if (!Array.isArray(a)) throw TypeError("matrix expected"); h = a.length; if (!Array.isArray(a[0])) { w = 1; r = Matrix(w, h); for(i = 0; i < h; i++) { r[0][i] = a[i]; } } else { w = a[0].length; r = Matrix(w, h); for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { r[j][i] = a[i][j]; } } } return r; }, check_square(a) { var a, n; if (!Array.isArray(a)) throw TypeError("array expected"); n = a.length; if (!Array.isArray(a[0]) || n != a[0].length) throw TypeError("square matrix expected"); return n; }, trace(a) { var n, r, i; n = Matrix.check_square(a); r = a[0][0]; for(i = 1; i < n; i++) { r += a[i][i]; } return r; }, charpoly(a) { var n, p, c, i, j, coef; n = Matrix.check_square(a); p = []; for(i = 0; i < n + 1; i++) p[i] = 0; p[n] = 1; c = Matrix.idn(n); for(i = 0; i < n; i++) { c = c * a; coef = -trace(c) / (i + 1); p[n - i - 1] = coef; for(j = 0; j < n; j++) c[j][j] += coef; } return Polynomial(p); }, eigenvals(a) { return Polynomial.roots(Matrix.charpoly(a)); }, det(a) { var n, i, j, k, s, src, v, c; n = Matrix.check_square(a); s = 1; src = a.dup(); for(i=0;i