| /* |
| * QuickJS Javascript Calculator |
| * |
| * Copyright (c) 2017-2020 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) { |
| global.Integer = global.BigInt; |
| global.Float = global.BigFloat; |
| global.algebraicMode = true; |
| |
| /* add non enumerable properties */ |
| function add_props(obj, props) { |
| var i, val, prop, tab, desc; |
| 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); |
| } |
| } |
| |
| /* same as proto[Symbol.operatorSet] = Operators.create(..op_list) |
| but allow shortcuts: left: [], right: [] or both |
| */ |
| function operators_set(proto, ...op_list) |
| { |
| var new_op_list, i, a, j, b, k, obj, tab; |
| var fields = [ "left", "right" ]; |
| new_op_list = []; |
| for(i = 0; i < op_list.length; i++) { |
| a = op_list[i]; |
| if (a.left || a.right) { |
| tab = [ a.left, a.right ]; |
| delete a.left; |
| delete a.right; |
| for(k = 0; k < 2; k++) { |
| obj = tab[k]; |
| if (obj) { |
| if (!Array.isArray(obj)) { |
| obj = [ obj ]; |
| } |
| for(j = 0; j < obj.length; j++) { |
| b = {}; |
| Object.assign(b, a); |
| b[fields[k]] = obj[j]; |
| new_op_list.push(b); |
| } |
| } |
| } |
| } else { |
| new_op_list.push(a); |
| } |
| } |
| proto[Symbol.operatorSet] = |
| Operators.create.call(null, ...new_op_list); |
| } |
| |
| /* 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) == 0) { |
| d >>= 1; |
| s++; |
| } |
| if (small_primes.length < t) |
| 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); |
| } |
| } |
| |
| /* math mode specific quirk to overload the integer division and power */ |
| Operators.updateBigIntOperators( |
| { |
| "/"(a, b) { |
| if (algebraicMode) { |
| return Fraction.toFraction(a, b); |
| } else { |
| return Float(a) / Float(b); |
| } |
| }, |
| "**"(a, b) { |
| if (algebraicMode) { |
| return generic_pow(a, b); |
| } else { |
| return Float(a) ** Float(b); |
| } |
| } |
| }); |
| |
| add_props(Integer, { |
| isInteger(a) { |
| /* integers are represented either as bigint or as number */ |
| return typeof a === "bigint" || |
| (typeof a === "number" && Number.isSafeInteger(a)); |
| }, |
| 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() { |
| var v = this; |
| if (v < 0) |
| v = -v; |
| return v; |
| }, |
| 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; |
| } |
| |
| function fraction_add(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); |
| } |
| function fraction_sub(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); |
| } |
| function fraction_mul(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| return Fraction.toFraction(a.num * b.num, a.den * b.den); |
| } |
| function fraction_div(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| return Fraction.toFraction(a.num * b.den, a.den * b.num); |
| } |
| function fraction_mod(a, b) { |
| var a1 = Fraction(a); |
| var b1 = Fraction(b); |
| return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; |
| } |
| function fraction_eq(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| /* we assume the fractions are normalized */ |
| return (a.num == b.num && a.den == b.den); |
| } |
| function fraction_lt(a, b) { |
| a = Fraction(a); |
| b = Fraction(b); |
| return (a.num * b.den < b.num * a.den); |
| } |
| |
| /* operators are needed for fractions */ |
| function float_add(a, b) { |
| return Float(a) + Float(b); |
| } |
| function float_sub(a, b) { |
| return Float(a) - Float(b); |
| } |
| function float_mul(a, b) { |
| return Float(a) * Float(b); |
| } |
| function float_div(a, b) { |
| return Float(a) / Float(b); |
| } |
| function float_mod(a, b) { |
| return Float(a) % Float(b); |
| } |
| function float_pow(a, b) { |
| return Float(a) ** Float(b); |
| } |
| function float_eq(a, b) { |
| /* XXX: may be better to use infinite precision for the comparison */ |
| return Float(a) === Float(b); |
| } |
| function float_lt(a, b) { |
| a = Float(a); |
| b = Float(b); |
| /* XXX: may be better to use infinite precision for the comparison */ |
| if (Float.isNaN(a) || Float.isNaN(b)) |
| return undefined; |
| else |
| return a < b; |
| } |
| |
| operators_set(Fraction.prototype, |
| { |
| "+": fraction_add, |
| "-": fraction_sub, |
| "*": fraction_mul, |
| "/": fraction_div, |
| "%": fraction_mod, |
| "**": generic_pow, |
| "==": fraction_eq, |
| "<": fraction_lt, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| return Fraction(-a.num, a.den); |
| }, |
| }, |
| { |
| left: [Number, BigInt], |
| right: [Number, BigInt], |
| "+": fraction_add, |
| "-": fraction_sub, |
| "*": fraction_mul, |
| "/": fraction_div, |
| "%": fraction_mod, |
| "**": generic_pow, |
| "==": fraction_eq, |
| "<": fraction_lt, |
| }, |
| { |
| left: Float, |
| right: Float, |
| "+": float_add, |
| "-": float_sub, |
| "*": float_mul, |
| "/": float_div, |
| "%": float_mod, |
| "**": float_pow, |
| "==": float_eq, |
| "<": float_lt, |
| }); |
| |
| add_props(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; |
| }, |
| }); |
| |
| add_props(Fraction.prototype, { |
| [Symbol.toPrimitive](hint) { |
| if (hint === "string") { |
| return this.toString(); |
| } else { |
| return Float(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; |
| 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.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() { |
| return Float.exp(this); |
| }, |
| log() { |
| if (this < 0) { |
| return Complex(this).log(); |
| } else { |
| return Float.log(this); |
| } |
| }, |
| }); |
| |
| /* Float */ |
| |
| 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.prototype, { |
| inverse() { |
| return 1.0 / this; |
| }, |
| norm2() { |
| return this * this; |
| }, |
| abs() { |
| return Float.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; |
| } |
| |
| |
| function complex_add(a, b) { |
| a = Complex(a); |
| b = Complex(b); |
| return Complex.toComplex(a.re + b.re, a.im + b.im); |
| } |
| function complex_sub(a, b) { |
| a = Complex(a); |
| b = Complex(b); |
| return Complex.toComplex(a.re - b.re, a.im - b.im); |
| } |
| function complex_mul(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); |
| } |
| function complex_div(a, b) { |
| a = Complex(a); |
| b = Complex(b); |
| return a * b.inverse(); |
| } |
| function complex_eq(a, b) { |
| a = Complex(a); |
| b = Complex(b); |
| return a.re == b.re && a.im == b.im; |
| } |
| |
| operators_set(Complex.prototype, |
| { |
| "+": complex_add, |
| "-": complex_sub, |
| "*": complex_mul, |
| "/": complex_div, |
| "**": generic_pow, |
| "==": complex_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| return Complex(-a.re, -a.im); |
| } |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction], |
| right: [Number, BigInt, Float, Fraction], |
| "+": complex_add, |
| "-": complex_sub, |
| "*": complex_mul, |
| "/": complex_div, |
| "**": generic_pow, |
| "==": complex_eq, |
| }); |
| |
| add_props(Complex, { |
| /* simplify to real number when possible */ |
| toComplex(re, im) { |
| if (algebraicMode && im == 0) |
| return re; |
| else |
| return Complex(re, im); |
| }, |
| }); |
| |
| add_props(Complex.prototype, { |
| 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; |
| }; |
| |
| function mod_add(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); |
| } |
| } |
| function mod_sub(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); |
| } |
| } |
| function mod_mul(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); |
| } |
| } |
| function mod_div(a, b) { |
| if (!(b instanceof Mod)) |
| b = Mod(b, a.mod); |
| return mod_mul(a, b.inverse()); |
| } |
| function mod_eq(a, b) { |
| return (a.mod == b.mod && a.res == b.res); |
| } |
| |
| operators_set(Mod.prototype, |
| { |
| "+": mod_add, |
| "-": mod_sub, |
| "*": mod_mul, |
| "/": mod_div, |
| "**": generic_pow, |
| "==": mod_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| return Mod(-a.res, a.mod); |
| } |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction], |
| right: [Number, BigInt, Float, Fraction], |
| "+": mod_add, |
| "-": mod_sub, |
| "*": mod_mul, |
| "/": mod_div, |
| "**": generic_pow, |
| }); |
| |
| add_props(Mod.prototype, { |
| 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 + ")"; |
| }, |
| }); |
| |
| /* Polynomial */ |
| |
| function polynomial_is_scalar(a) |
| { |
| if (typeof a === "number" || |
| typeof a === "bigint" || |
| typeof a === "bigfloat") |
| return true; |
| if (a instanceof Fraction || |
| a instanceof Complex || |
| a instanceof Mod) |
| return true; |
| return false; |
| } |
| |
| 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 (polynomial_is_scalar(a)) { |
| 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; |
| }, |
| 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; |
| }, |
| }); |
| |
| |
| function polynomial_add(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); |
| } |
| function polynomial_sub(a, b) { |
| return polynomial_add(a, -b); |
| } |
| function polynomial_mul(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); |
| } |
| function polynomial_div_scalar(a, b) { |
| return a * (1 / b); |
| } |
| function polynomial_div(a, b) |
| { |
| return RationalFunction(Polynomial(a), |
| Polynomial(b)); |
| } |
| function polynomial_mod(a, b) { |
| return Polynomial.divrem(a, b)[1]; |
| } |
| function polynomial_eq(a, b) { |
| var n, i; |
| n = a.length; |
| if (n != b.length) |
| return false; |
| for(i = 0; i < n; i++) { |
| if (a[i] != b[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| operators_set(Polynomial.prototype, |
| { |
| "+": polynomial_add, |
| "-": polynomial_sub, |
| "*": polynomial_mul, |
| "/": polynomial_div, |
| "**": generic_pow, |
| "==": polynomial_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| var r, i, n, a; |
| n = a.length; |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = -a[i]; |
| return Polynomial(r); |
| }, |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction, Complex, Mod], |
| "+": polynomial_add, |
| "-": polynomial_sub, |
| "*": polynomial_mul, |
| "/": polynomial_div, |
| "**": generic_pow, /* XXX: only for integer */ |
| }, |
| { |
| right: [Number, BigInt, Float, Fraction, Complex, Mod], |
| "+": polynomial_add, |
| "-": polynomial_sub, |
| "*": polynomial_mul, |
| "/": polynomial_div_scalar, |
| "**": generic_pow, /* XXX: only for integer */ |
| }); |
| |
| add_props(Polynomial, { |
| 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; |
| }; |
| |
| function polymod_add(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); |
| } |
| } |
| function polymod_sub(a, b) { |
| return polymod_add(a, -b); |
| } |
| function polymod_mul(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); |
| } |
| } |
| function polymod_div(a, b) { |
| if (!(b instanceof PolyMod)) |
| b = PolyMod(b, a.mod); |
| return polymod_mul(a, b.inverse()); |
| } |
| function polymod_eq(a, b) { |
| return (a.mod == b.mod && a.res == b.res); |
| } |
| |
| operators_set(PolyMod.prototype, |
| { |
| "+": polymod_add, |
| "-": polymod_sub, |
| "*": polymod_mul, |
| "/": polymod_div, |
| "**": generic_pow, |
| "==": polymod_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| return PolyMod(-a.res, a.mod); |
| }, |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| "+": polymod_add, |
| "-": polymod_sub, |
| "*": polymod_mul, |
| "/": polymod_div, |
| "**": generic_pow, /* XXX: only for integer */ |
| }); |
| |
| add_props(PolyMod.prototype, { |
| 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 + ")"; |
| }, |
| }); |
| |
| /* 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, { |
| 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); |
| }, |
| }); |
| |
| function ratfunc_add(a, b) { |
| a = RationalFunction.toRationalFunction(a); |
| b = RationalFunction.toRationalFunction(b); |
| return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); |
| } |
| function ratfunc_sub(a, b) { |
| a = RationalFunction.toRationalFunction(a); |
| b = RationalFunction.toRationalFunction(b); |
| return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); |
| } |
| function ratfunc_mul(a, b) { |
| a = RationalFunction.toRationalFunction(a); |
| b = RationalFunction.toRationalFunction(b); |
| return RationalFunction(a.num * b.num, a.den * b.den); |
| } |
| function ratfunc_div(a, b) { |
| a = RationalFunction.toRationalFunction(a); |
| b = RationalFunction.toRationalFunction(b); |
| return RationalFunction(a.num * b.den, a.den * b.num); |
| } |
| function ratfunc_eq(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); |
| } |
| |
| operators_set(RationalFunction.prototype, |
| { |
| "+": ratfunc_add, |
| "-": ratfunc_sub, |
| "*": ratfunc_mul, |
| "/": ratfunc_div, |
| "**": generic_pow, |
| "==": ratfunc_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| return RationalFunction(-this.num, this.den); |
| }, |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| "+": ratfunc_add, |
| "-": ratfunc_sub, |
| "*": ratfunc_mul, |
| "/": ratfunc_div, |
| "**": generic_pow, /* should only be used with integers */ |
| }); |
| |
| add_props(RationalFunction, { |
| /* 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; |
| } |
| }, |
| }); |
| |
| /* 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; |
| }; |
| |
| function series_is_scalar_or_polynomial(a) |
| { |
| return polynomial_is_scalar(a) || |
| (a instanceof Polynomial); |
| } |
| |
| /* 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 (series_is_scalar_or_polynomial(a)) { |
| 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"); |
| } |
| }; |
| |
| function series_add(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 (series_is_scalar_or_polynomial(v2)) { |
| 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(); |
| } |
| function series_sub(a, b) { |
| return series_add(a, -b); |
| } |
| function series_mul(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(); |
| } |
| function series_div(v1, v2) { |
| if (!(v2 instanceof Series)) |
| v2 = Series(v2, v1.length); |
| return series_mul(v1, v2.inverse()); |
| } |
| function series_pow(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); |
| } |
| } |
| function series_eq(a, b) { |
| var n, i; |
| 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; |
| } |
| |
| operators_set(Series.prototype, |
| { |
| "+": series_add, |
| "-": series_sub, |
| "*": series_mul, |
| "/": series_div, |
| "**": series_pow, |
| "==": series_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| var obj, n, i; |
| n = a.length; |
| obj = Series.zero(a.length, a.emin); |
| for(i = 0; i < n; i++) { |
| obj[i] = -a[i]; |
| } |
| return obj; |
| }, |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], |
| "+": series_add, |
| "-": series_sub, |
| "*": series_mul, |
| "/": series_div, |
| "**": series_pow, |
| }); |
| |
| add_props(Series.prototype, { |
| 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 RangeError("cannot represent integ(1/X)"); |
| } else { |
| r[i] = a[i] / (j + 1); |
| } |
| } |
| return r.trim(); |
| }, |
| exp() { |
| var c, i, r, n, a = this; |
| if (a.emin < 0) |
| throw RangeError("negative exponent in exp"); |
| n = a.emin + a.length; |
| if (a.emin > 0 || a[0] == 0) { |
| c = 1; |
| } else { |
| c = global.exp(a[0]); |
| a -= a[0]; |
| } |
| 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 RangeError("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, { |
| /* 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; |
| }, |
| O(a) { |
| function ErrorO() { |
| return TypeError("invalid O() argument"); |
| } |
| var n; |
| if (series_is_scalar_or_polynomial(a)) { |
| 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<n;i++) { |
| for(j = i; j < n; j++) { |
| if (src[j][i] != 0) |
| break; |
| } |
| if (j == n) |
| return 0; |
| if (j != i) { |
| for(k = 0;k < n; k++) { |
| v = src[j][k]; |
| src[j][k] = src[i][k]; |
| src[i][k] = v; |
| } |
| s = -s; |
| } |
| c = src[i][i].inverse(); |
| for(j = i + 1; j < n; j++) { |
| v = c * src[j][i]; |
| for(k = 0;k < n; k++) { |
| src[j][k] -= src[i][k] * v; |
| } |
| } |
| } |
| c = s; |
| for(i=0;i<n;i++) |
| c *= src[i][i]; |
| return c; |
| }, |
| inverse(a) { |
| var n, dst, src, i, j, k, n2, r, c, v; |
| n = Matrix.check_square(a); |
| src = a.dup(); |
| dst = Matrix.idn(n); |
| for(i=0;i<n;i++) { |
| for(j = i; j < n; j++) { |
| if (src[j][i] != 0) |
| break; |
| } |
| if (j == n) |
| throw RangeError("matrix is not invertible"); |
| if (j != i) { |
| /* swap lines in src and dst */ |
| v = src[j]; |
| src[j] = src[i]; |
| src[i] = v; |
| v = dst[j]; |
| dst[j] = dst[i]; |
| dst[i] = v; |
| } |
| |
| c = src[i][i].inverse(); |
| for(k = 0; k < n; k++) { |
| src[i][k] *= c; |
| dst[i][k] *= c; |
| } |
| |
| for(j = 0; j < n; j++) { |
| if (j != i) { |
| c = src[j][i]; |
| for(k = i; k < n; k++) { |
| src[j][k] -= src[i][k] * c; |
| } |
| for(k = 0; k < n; k++) { |
| dst[j][k] -= dst[i][k] * c; |
| } |
| } |
| } |
| } |
| return dst; |
| }, |
| rank(a) { |
| var src, i, j, k, w, h, l, c; |
| |
| if (!Array.isArray(a) || |
| !Array.isArray(a[0])) |
| throw TypeError("matrix expected"); |
| h = a.length; |
| w = a[0].length; |
| src = a.dup(); |
| l = 0; |
| for(i=0;i<w;i++) { |
| for(j = l; j < h; j++) { |
| if (src[j][i] != 0) |
| break; |
| } |
| if (j == h) |
| continue; |
| if (j != l) { |
| /* swap lines */ |
| for(k = 0; k < w; k++) { |
| v = src[j][k]; |
| src[j][k] = src[l][k]; |
| src[l][k] = v; |
| } |
| } |
| |
| c = src[l][i].inverse(); |
| for(k = 0; k < w; k++) { |
| src[l][k] *= c; |
| } |
| |
| for(j = l + 1; j < h; j++) { |
| c = src[j][i]; |
| for(k = i; k < w; k++) { |
| src[j][k] -= src[l][k] * c; |
| } |
| } |
| l++; |
| } |
| return l; |
| }, |
| ker(a) { |
| var src, i, j, k, w, h, l, m, r, im_cols, ker_dim, c; |
| |
| if (!Array.isArray(a) || |
| !Array.isArray(a[0])) |
| throw TypeError("matrix expected"); |
| h = a.length; |
| w = a[0].length; |
| src = a.dup(); |
| im_cols = []; |
| l = 0; |
| for(i=0;i<w;i++) { |
| im_cols[i] = false; |
| for(j = l; j < h; j++) { |
| if (src[j][i] != 0) |
| break; |
| } |
| if (j == h) |
| continue; |
| im_cols[i] = true; |
| if (j != l) { |
| /* swap lines */ |
| for(k = 0; k < w; k++) { |
| v = src[j][k]; |
| src[j][k] = src[l][k]; |
| src[l][k] = v; |
| } |
| } |
| |
| c = src[l][i].inverse(); |
| for(k = 0; k < w; k++) { |
| src[l][k] *= c; |
| } |
| |
| for(j = 0; j < h; j++) { |
| if (j != l) { |
| c = src[j][i]; |
| for(k = i; k < w; k++) { |
| src[j][k] -= src[l][k] * c; |
| } |
| } |
| } |
| l++; |
| // log_str("m=" + cval_toString(v1) + "\n"); |
| } |
| // log_str("im cols="+im_cols+"\n"); |
| |
| /* build the kernel vectors */ |
| ker_dim = w - l; |
| r = Matrix(w, ker_dim); |
| k = 0; |
| for(i = 0; i < w; i++) { |
| if (!im_cols[i]) { |
| /* select this column from the matrix */ |
| l = 0; |
| m = 0; |
| for(j = 0; j < w; j++) { |
| if (im_cols[j]) { |
| r[j][k] = -src[m][i]; |
| m++; |
| } else { |
| if (l == k) { |
| r[j][k] = 1; |
| } else { |
| r[j][k] = 0; |
| } |
| l++; |
| } |
| } |
| k++; |
| } |
| } |
| return r; |
| }, |
| dp(a, b) { |
| var i, n, r; |
| n = a.length; |
| if (n != b.length) |
| throw TypeError("incompatible array length"); |
| /* XXX: could do complex product */ |
| r = 0; |
| for(i = 0; i < n; i++) { |
| r += a[i] * b[i]; |
| } |
| return r; |
| }, |
| /* cross product */ |
| cp(v1, v2) { |
| var r; |
| if (v1.length != 3 || v2.length != 3) |
| throw TypeError("vectors must have 3 elements"); |
| r = []; |
| r[0] = v1[1] * v2[2] - v1[2] * v2[1]; |
| r[1] = v1[2] * v2[0] - v1[0] * v2[2]; |
| r[2] = v1[0] * v2[1] - v1[1] * v2[0]; |
| return r; |
| }, |
| }); |
| |
| function array_add(a, b) { |
| var r, i, n; |
| n = a.length; |
| if (n != b.length) |
| throw TypeError("incompatible array size"); |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = a[i] + b[i]; |
| return r; |
| } |
| function array_sub(a, b) { |
| var r, i, n; |
| n = a.length; |
| if (n != b.length) |
| throw TypeError("incompatible array size"); |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = a[i] - b[i]; |
| return r; |
| } |
| function array_scalar_mul(a, b) { |
| var r, i, n; |
| n = a.length; |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = a[i] * b; |
| return r; |
| } |
| function array_mul(a, b) { |
| var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat; |
| h = a.length; |
| a_mat = Array.isArray(a[0]); |
| if (a_mat) { |
| l = a[0].length; |
| } else { |
| l = 1; |
| } |
| if (l != b.length) |
| throw RangeError("incompatible matrix size"); |
| b_mat = Array.isArray(b[0]); |
| if (b_mat) |
| w = b[0].length; |
| else |
| w = 1; |
| r = []; |
| if (a_mat && b_mat) { |
| for(i = 0; i < h; i++) { |
| rl = []; |
| for(j = 0; j < w; j++) { |
| sum = 0; |
| for(k = 0; k < l; k++) { |
| sum += a[i][k] * b[k][j]; |
| } |
| rl[j] = sum; |
| } |
| r[i] = rl; |
| } |
| } else if (a_mat && !b_mat) { |
| for(i = 0; i < h; i++) { |
| sum = 0; |
| for(k = 0; k < l; k++) { |
| sum += a[i][k] * b[k]; |
| } |
| r[i] = sum; |
| } |
| } else if (!a_mat && b_mat) { |
| for(i = 0; i < h; i++) { |
| rl = []; |
| for(j = 0; j < w; j++) { |
| rl[j] = a[i] * b[0][j]; |
| } |
| r[i] = rl; |
| } |
| } else { |
| for(i = 0; i < h; i++) { |
| r[i] = a[i] * b[0]; |
| } |
| } |
| return r; |
| } |
| function array_div(a, b) { |
| return array_mul(a, b.inverse()); |
| } |
| function array_scalar_div(a, b) { |
| return a * b.inverse(); |
| } |
| function array_eq(a, b) { |
| var n, i; |
| n = a.length; |
| if (n != b.length) |
| return false; |
| for(i = 0; i < n; i++) { |
| if (a[i] != b[i]) |
| return false; |
| } |
| return true; |
| } |
| |
| operators_set(Array.prototype, |
| { |
| "+": array_add, |
| "-": array_sub, |
| "*": array_mul, |
| "/": array_div, |
| "==": array_eq, |
| "pos"(a) { |
| return a; |
| }, |
| "neg"(a) { |
| var i, n, r; |
| n = a.length; |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = -a[i]; |
| return r; |
| } |
| }, |
| { |
| right: [Number, BigInt, Float, Fraction, Complex, Mod, |
| Polynomial, PolyMod, RationalFunction, Series], |
| "*": array_scalar_mul, |
| "/": array_scalar_div, |
| "**": generic_pow, /* XXX: only for integer */ |
| }, |
| { |
| left: [Number, BigInt, Float, Fraction, Complex, Mod, |
| Polynomial, PolyMod, RationalFunction, Series], |
| "*"(a, b) { return array_scalar_mul(b, a); }, |
| "/"(a, b) { return array_scalar_div(b, a); }, |
| }); |
| |
| add_props(Array.prototype, { |
| conj() { |
| var i, n, r; |
| n = this.length; |
| r = []; |
| for(i = 0; i < n; i++) |
| r[i] = this[i].conj(); |
| return r; |
| }, |
| dup() { |
| var r, i, n, el, a = this; |
| r = []; |
| n = a.length; |
| for(i = 0; i < n; i++) { |
| el = a[i]; |
| if (Array.isArray(el)) |
| el = el.dup(); |
| r[i] = el; |
| } |
| return r; |
| }, |
| inverse() { |
| return Matrix.inverse(this); |
| }, |
| norm2: Polynomial.prototype.norm2, |
| }); |
| |
| })(this); |
| |
| /* global definitions */ |
| var I = Complex(0, 1); |
| var X = Polynomial([0, 1]); |
| var O = Series.O; |
| |
| Object.defineProperty(this, "PI", { get: function () { return Float.PI } }); |
| |
| /* put frequently used functions in the global context */ |
| var gcd = Integer.gcd; |
| var fact = Integer.fact; |
| var comb = Integer.comb; |
| var pmod = Integer.pmod; |
| var invmod = Integer.invmod; |
| var factor = Integer.factor; |
| var isprime = Integer.isPrime; |
| var nextprime = Integer.nextPrime; |
| |
| function deriv(a) |
| { |
| return a.deriv(); |
| } |
| |
| function integ(a) |
| { |
| return a.integ(); |
| } |
| |
| function norm2(a) |
| { |
| return a.norm2(); |
| } |
| |
| function abs(a) |
| { |
| return a.abs(); |
| } |
| |
| function conj(a) |
| { |
| return a.conj(); |
| } |
| |
| function arg(a) |
| { |
| return a.arg(); |
| } |
| |
| function inverse(a) |
| { |
| return a.inverse(); |
| } |
| |
| function trunc(a) |
| { |
| if (Integer.isInteger(a)) { |
| return a; |
| } else if (a instanceof Fraction) { |
| return Integer.tdiv(a.num, a.den); |
| } else if (a instanceof Polynomial) { |
| return a; |
| } else if (a instanceof RationalFunction) { |
| return Polynomial.divrem(a.num, a.den)[0]; |
| } else { |
| return Float.ceil(a); |
| } |
| } |
| |
| function floor(a) |
| { |
| if (Integer.isInteger(a)) { |
| return a; |
| } else if (a instanceof Fraction) { |
| return Integer.fdiv(a.num, a.den); |
| } else { |
| return Float.floor(a); |
| } |
| } |
| |
| function ceil(a) |
| { |
| if (Integer.isInteger(a)) { |
| return a; |
| } else if (a instanceof Fraction) { |
| return Integer.cdiv(a.num, a.den); |
| } else { |
| return Float.ceil(a); |
| } |
| } |
| |
| function sqrt(a) |
| { |
| var t, u, re, im; |
| if (a instanceof Series) { |
| return a ^ (1/2); |
| } else if (a instanceof Complex) { |
| t = abs(a); |
| u = a.re; |
| re = sqrt((t + u) / 2); |
| im = sqrt((t - u) / 2); |
| if (a.im < 0) |
| im = -im; |
| return Complex.toComplex(re, im); |
| } else { |
| a = Float(a); |
| if (a < 0) { |
| return Complex(0, Float.sqrt(-a)); |
| } else { |
| return Float.sqrt(a); |
| } |
| } |
| } |
| |
| function exp(a) |
| { |
| return a.exp(); |
| } |
| |
| function log(a) |
| { |
| return a.log(); |
| } |
| |
| function log2(a) |
| { |
| return log(a) * Float.LOG2E; |
| } |
| |
| function log10(a) |
| { |
| return log(a) * Float.LOG10E; |
| } |
| |
| function todb(a) |
| { |
| return log10(a) * 10; |
| } |
| |
| function fromdb(a) |
| { |
| return 10 ^ (a / 10); |
| } |
| |
| function sin(a) |
| { |
| var t; |
| if (a instanceof Complex || a instanceof Series) { |
| t = exp(a * I); |
| return (t - 1/t) / (2 * I); |
| } else { |
| return Float.sin(Float(a)); |
| } |
| } |
| |
| function cos(a) |
| { |
| var t; |
| if (a instanceof Complex || a instanceof Series) { |
| t = exp(a * I); |
| return (t + 1/t) / 2; |
| } else { |
| return Float.cos(Float(a)); |
| } |
| } |
| |
| function tan(a) |
| { |
| if (a instanceof Complex || a instanceof Series) { |
| return sin(a) / cos(a); |
| } else { |
| return Float.tan(Float(a)); |
| } |
| } |
| |
| function asin(a) |
| { |
| return Float.asin(Float(a)); |
| } |
| |
| function acos(a) |
| { |
| return Float.acos(Float(a)); |
| } |
| |
| function atan(a) |
| { |
| return Float.atan(Float(a)); |
| } |
| |
| function atan2(a, b) |
| { |
| return Float.atan2(Float(a), Float(b)); |
| } |
| |
| function sinc(a) |
| { |
| if (a == 0) { |
| return 1; |
| } else { |
| a *= Float.PI; |
| return sin(a) / a; |
| } |
| } |
| |
| function todeg(a) |
| { |
| return a * 180 / Float.PI; |
| } |
| |
| function fromdeg(a) |
| { |
| return a * Float.PI / 180; |
| } |
| |
| function sinh(a) |
| { |
| var e = Float.exp(Float(a)); |
| return (e - 1/e) * 0.5; |
| } |
| |
| function cosh(a) |
| { |
| var e = Float.exp(Float(a)); |
| return (e + 1/e) * 0.5; |
| } |
| |
| function tanh(a) |
| { |
| var e = Float.exp(Float(a) * 2); |
| return (e - 1) / (e + 1); |
| } |
| |
| function asinh(a) |
| { |
| var x = Float(a); |
| return log(sqrt(x * x + 1) + x); |
| } |
| |
| function acosh(a) |
| { |
| var x = Float(a); |
| return log(sqrt(x * x - 1) + x); |
| } |
| |
| function atanh(a) |
| { |
| var x = Float(a); |
| return 0.5 * log((1 + x) / (1 - x)); |
| } |
| |
| var idn = Matrix.idn; |
| var diag = Matrix.diag; |
| var trans = Matrix.trans; |
| var trace = Matrix.trace; |
| var charpoly = Matrix.charpoly; |
| var eigenvals = Matrix.eigenvals; |
| var det = Matrix.det; |
| var rank = Matrix.rank; |
| var ker = Matrix.ker; |
| var cp = Matrix.cp; |
| var dp = Matrix.dp; |
| |
| var polroots = Polynomial.roots; |
| var bestappr = Float.bestappr; |