1/*
2 * QuickJS Javascript Calculator
3 *
4 * Copyright (c) 2017-2020 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24"use strict";
25"use math";
26
27var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix;
28
29(function(global) {
30    global.Integer = global.BigInt;
31    global.Float = global.BigFloat;
32    global.algebraicMode = true;
33
34    /* add non enumerable properties */
35    function add_props(obj, props) {
36        var i, val, prop, tab, desc;
37        tab = Reflect.ownKeys(props);
38        for(i = 0; i < tab.length; i++) {
39            prop = tab[i];
40            desc = Object.getOwnPropertyDescriptor(props, prop);
41            desc.enumerable = false;
42            if ("value" in desc) {
43                if (typeof desc.value !== "function") {
44                    desc.writable = false;
45                    desc.configurable = false;
46                }
47            } else {
48                /* getter/setter */
49                desc.configurable = false;
50            }
51            Object.defineProperty(obj, prop, desc);
52        }
53    }
54
55    /* same as proto[Symbol.operatorSet] = Operators.create(..op_list)
56       but allow shortcuts: left: [], right: [] or both
57    */
58    function operators_set(proto, ...op_list)
59    {
60        var new_op_list, i, a, j, b, k, obj, tab;
61        var fields = [ "left", "right" ];
62        new_op_list = [];
63        for(i = 0; i < op_list.length; i++) {
64            a = op_list[i];
65            if (a.left || a.right) {
66                tab = [ a.left, a.right ];
67                delete a.left;
68                delete a.right;
69                for(k = 0; k < 2; k++) {
70                    obj = tab[k];
71                    if (obj) {
72                        if (!Array.isArray(obj)) {
73                            obj = [ obj ];
74                        }
75                        for(j = 0; j < obj.length; j++) {
76                            b = {};
77                            Object.assign(b, a);
78                            b[fields[k]] = obj[j];
79                            new_op_list.push(b);
80                        }
81                    }
82                }
83            } else {
84                new_op_list.push(a);
85            }
86        }
87        proto[Symbol.operatorSet] =
88            Operators.create.call(null, ...new_op_list);
89    }
90
91    /* Integer */
92
93    function generic_pow(a, b) {
94        var r, is_neg, i;
95        if (!Integer.isInteger(b)) {
96            return exp(log(a) * b);
97        }
98        if (Array.isArray(a) && !(a instanceof Polynomial ||
99                                  a instanceof Series)) {
100            r = idn(Matrix.check_square(a));
101        } else {
102            r = 1;
103        }
104        if (b == 0)
105            return r;
106        is_neg = false;
107        if (b < 0) {
108            is_neg = true;
109            b = -b;
110        }
111        r = a;
112        for(i = Integer.floorLog2(b) - 1; i >= 0; i--) {
113            r *= r;
114            if ((b >> i) & 1)
115                r *= a;
116        }
117        if (is_neg) {
118            if (typeof r.inverse != "function")
119                throw "negative powers are not supported for this type";
120            r = r.inverse();
121        }
122        return r;
123    }
124
125    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 ];
126
127    function miller_rabin_test(n, t) {
128        var d, r, s, i, j, a;
129        d = n - 1;
130        s = 0;
131        while ((d & 1) == 0) {
132            d >>= 1;
133            s++;
134        }
135        if (small_primes.length < t)
136            t = small_primes.length;
137        loop: for(j = 0; j < t; j++) {
138            a = small_primes[j];
139            r = Integer.pmod(a, d, n);
140            if (r == 1 || r == (n - 1))
141                continue;
142            for(i = 1; i < s; i++) {
143                r = (r * r) % n;
144                if (r == 1)
145                    return false;
146                if (r == (n - 1))
147                    continue loop;
148            }
149            return false; /* n is composite */
150        }
151        return true; /* n is probably prime with probability (1-0.5^t) */
152    }
153
154    function fact_rec(a, b) {  /* assumes a <= b */
155        var i, r;
156        if ((b - a) <= 5) {
157            r = a;
158            for(i = a + 1; i <= b; i++)
159                r *= i;
160            return r;
161        } else {
162            /* to avoid a quadratic running time it is better to
163               multiply numbers of similar size */
164            i = (a + b) >> 1;
165            return fact_rec(a, i) * fact_rec(i + 1, b);
166        }
167    }
168
169    /* math mode specific quirk to overload the integer division and power */
170    Operators.updateBigIntOperators(
171        {
172            "/"(a, b) {
173                if (algebraicMode) {
174                    return Fraction.toFraction(a, b);
175                } else {
176                    return Float(a) / Float(b);
177                }
178            },
179            "**"(a, b) {
180                if (algebraicMode) {
181                    return generic_pow(a, b);
182                } else {
183                    return Float(a) ** Float(b);
184                }
185            }
186        });
187
188    add_props(Integer, {
189        isInteger(a) {
190            /* integers are represented either as bigint or as number */
191            return typeof a === "bigint" ||
192                (typeof a === "number" && Number.isSafeInteger(a));
193        },
194        gcd(a, b) {
195            var r;
196            while (b != 0) {
197                r = a % b;
198                a = b;
199                b = r;
200            }
201            return a;
202        },
203        fact(n) {
204            return n <= 0 ? 1 : fact_rec(1, n);
205        },
206        /* binomial coefficient */
207        comb(n, k) {
208            if (k < 0 || k > n)
209                return 0;
210            if (k > n - k)
211                k = n - k;
212            if (k == 0)
213                return 1;
214            return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k));
215        },
216        /* inverse of x modulo y */
217        invmod(x, y) {
218            var q, u, v, a, c, t;
219            u = x;
220            v = y;
221            c = 1;
222            a = 0;
223            while (u != 0) {
224                t = Integer.fdivrem(v, u);
225                q = t[0];
226                v = u;
227                u = t[1];
228                t = c;
229                c = a - q * c;
230                a = t;
231            }
232            /* v = gcd(x, y) */
233            if (v != 1)
234                throw RangeError("not invertible");
235            return a % y;
236        },
237        /* return a ^ b modulo m */
238        pmod(a, b, m) {
239            var r;
240            if (b == 0)
241                return 1;
242            if (b < 0) {
243                a = Integer.invmod(a, m);
244                b = -b;
245            }
246            r = 1;
247            for(;;) {
248                if (b & 1) {
249                    r = (r * a) % m;
250                }
251                b >>= 1;
252                if (b == 0)
253                    break;
254                a = (a * a) % m;
255            }
256            return r;
257        },
258
259        /* return true if n is prime (or probably prime with
260           probability 1-0.5^t) */
261        isPrime(n, t) {
262            var i, d, n1;
263            if (!Integer.isInteger(n))
264                throw TypeError("invalid type");
265            if (n <= 1)
266                return false;
267            n1 = small_primes.length;
268            /* XXX: need Integer.sqrt() */
269            for(i = 0; i < n1; i++) {
270                d = small_primes[i];
271                if (d == n)
272                    return true;
273                if (d > n)
274                    return false;
275                if ((n % d) == 0)
276                    return false;
277            }
278            if (n < d * d)
279                return true;
280            if (typeof t == "undefined")
281                t = 64;
282            return miller_rabin_test(n, t);
283        },
284        nextPrime(n) {
285            if (!Integer.isInteger(n))
286                throw TypeError("invalid type");
287            if (n < 1)
288                n = 1;
289            for(;;) {
290                n++;
291                if (Integer.isPrime(n))
292                    return n;
293            }
294        },
295        factor(n) {
296            var r, d;
297            if (!Integer.isInteger(n))
298                throw TypeError("invalid type");
299            r = [];
300            if (abs(n) <= 1) {
301                r.push(n);
302                return r;
303            }
304            if (n < 0) {
305                r.push(-1);
306                n = -n;
307            }
308
309            while ((n % 2) == 0) {
310                n >>= 1;
311                r.push(2);
312            }
313
314            d = 3;
315            while (n != 1) {
316                if (Integer.isPrime(n)) {
317                    r.push(n);
318                    break;
319                }
320                /* we are sure there is at least one divisor, so one test */
321                for(;;) {
322                    if ((n % d) == 0)
323                        break;
324                    d += 2;
325                }
326                for(;;) {
327                    r.push(d);
328                    n = Integer.tdiv(n, d);
329                    if ((n % d) != 0)
330                        break;
331                }
332            }
333            return r;
334        },
335    });
336
337    add_props(Integer.prototype, {
338        inverse() {
339            return 1 / this;
340        },
341        norm2() {
342            return this * this;
343        },
344        abs() {
345            var v = this;
346            if (v < 0)
347                v = -v;
348            return v;
349        },
350        conj() {
351            return this;
352        },
353        arg() {
354            if (this >= 0)
355                return 0;
356            else
357                return Float.PI;
358        },
359        exp() {
360            if (this == 0)
361                return 1;
362            else
363                return Float.exp(this);
364        },
365        log() {
366            if (this == 1)
367                return 0;
368            else
369                return Float(this).log();
370        },
371    });
372
373    /* Fraction */
374
375    Fraction = function Fraction(a, b)
376    {
377        var d, r, obj;
378
379        if (new.target)
380            throw TypeError("not a constructor");
381        if (a instanceof Fraction)
382            return a;
383        if (!Integer.isInteger(a))
384            throw TypeError("integer expected");
385        if (typeof b === "undefined") {
386            b = 1;
387        } else {
388            if (!Integer.isInteger(b))
389                throw TypeError("integer expected");
390            if (b == 0)
391                throw RangeError("division by zero");
392            d = Integer.gcd(a, b);
393            if (d != 1) {
394                a = Integer.tdiv(a, d);
395                b = Integer.tdiv(b, d);
396            }
397
398            /* the fractions are normalized with den > 0 */
399            if (b < 0) {
400                a = -a;
401                b = -b;
402            }
403        }
404        obj = Object.create(Fraction.prototype);
405        obj.num = a;
406        obj.den = b;
407        return obj;
408    }
409
410    function fraction_add(a, b) {
411        a = Fraction(a);
412        b = Fraction(b);
413        return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den);
414    }
415    function fraction_sub(a, b) {
416        a = Fraction(a);
417        b = Fraction(b);
418        return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den);
419    }
420    function fraction_mul(a, b) {
421        a = Fraction(a);
422        b = Fraction(b);
423        return Fraction.toFraction(a.num * b.num, a.den * b.den);
424    }
425    function fraction_div(a, b) {
426        a = Fraction(a);
427        b = Fraction(b);
428        return Fraction.toFraction(a.num * b.den, a.den * b.num);
429    }
430    function fraction_mod(a, b) {
431        var a1 = Fraction(a);
432        var b1 = Fraction(b);
433        return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b;
434    }
435    function fraction_eq(a, b) {
436        a = Fraction(a);
437        b = Fraction(b);
438        /* we assume the fractions are normalized */
439        return (a.num == b.num && a.den == b.den);
440    }
441    function fraction_lt(a, b) {
442        a = Fraction(a);
443        b = Fraction(b);
444        return (a.num * b.den < b.num * a.den);
445    }
446
447    /* operators are needed for fractions */
448    function float_add(a, b) {
449        return Float(a) + Float(b);
450    }
451    function float_sub(a, b) {
452        return Float(a) - Float(b);
453    }
454    function float_mul(a, b) {
455        return Float(a) * Float(b);
456    }
457    function float_div(a, b) {
458        return Float(a) / Float(b);
459    }
460    function float_mod(a, b) {
461        return Float(a) % Float(b);
462    }
463    function float_pow(a, b) {
464        return Float(a) ** Float(b);
465    }
466    function float_eq(a, b) {
467        /* XXX: may be better to use infinite precision for the comparison */
468        return Float(a) === Float(b);
469    }
470    function float_lt(a, b) {
471        a = Float(a);
472        b = Float(b);
473        /* XXX: may be better to use infinite precision for the comparison */
474        if (Float.isNaN(a) || Float.isNaN(b))
475            return undefined;
476        else
477            return a < b;
478    }
479
480    operators_set(Fraction.prototype,
481        {
482            "+": fraction_add,
483            "-": fraction_sub,
484            "*": fraction_mul,
485            "/": fraction_div,
486            "%": fraction_mod,
487            "**": generic_pow,
488            "==": fraction_eq,
489            "<": fraction_lt,
490            "pos"(a) {
491                return a;
492            },
493            "neg"(a) {
494                return Fraction(-a.num, a.den);
495            },
496        },
497        {
498            left: [Number, BigInt],
499            right: [Number, BigInt],
500            "+": fraction_add,
501            "-": fraction_sub,
502            "*": fraction_mul,
503            "/": fraction_div,
504            "%": fraction_mod,
505            "**": generic_pow,
506            "==": fraction_eq,
507            "<": fraction_lt,
508        },
509        {
510            left: Float,
511            right: Float,
512            "+": float_add,
513            "-": float_sub,
514            "*": float_mul,
515            "/": float_div,
516            "%": float_mod,
517            "**": float_pow,
518            "==": float_eq,
519            "<": float_lt,
520        });
521
522    add_props(Fraction, {
523        /* (internal use) simplify 'a' to an integer when possible */
524        toFraction(a, b) {
525            var r = Fraction(a, b);
526            if (algebraicMode && r.den == 1)
527                return r.num;
528            else
529                return r;
530        },
531    });
532
533    add_props(Fraction.prototype, {
534        [Symbol.toPrimitive](hint) {
535            if (hint === "string") {
536                return this.toString();
537            } else {
538                return Float(this.num) / this.den;
539            }
540        },
541        inverse() {
542            return Fraction(this.den, this.num);
543        },
544        toString() {
545            return this.num + "/" + this.den;
546        },
547        norm2() {
548            return this * this;
549        },
550        abs() {
551            if (this.num < 0)
552                return -this;
553            else
554                return this;
555        },
556        conj() {
557            return this;
558        },
559        arg() {
560            if (this.num >= 0)
561                return 0;
562            else
563                return Float.PI;
564        },
565        exp() {
566            return Float.exp(Float(this));
567        },
568        log() {
569            return Float(this).log();
570        },
571    });
572
573    /* Number (Float64) */
574
575    add_props(Number.prototype, {
576        inverse() {
577            return 1 / this;
578        },
579        norm2() {
580            return this * this;
581        },
582        abs() {
583            return Math.abs(this);
584        },
585        conj() {
586            return this;
587        },
588        arg() {
589            if (this >= 0)
590                return 0;
591            else
592                return Float.PI;
593        },
594        exp() {
595            return Float.exp(this);
596        },
597        log() {
598            if (this < 0) {
599                return Complex(this).log();
600            } else {
601                return Float.log(this);
602            }
603        },
604    });
605
606    /* Float */
607
608    var const_tab = [];
609
610    /* we cache the constants for small precisions */
611    function get_const(n) {
612        var t, c, p;
613        t = const_tab[n];
614        p = BigFloatEnv.prec;
615        if (t && t.prec == p) {
616            return t.val;
617        } else {
618            switch(n) {
619            case 0: c = Float.exp(1); break;
620            case 1: c = Float.log(10); break;
621//            case 2: c = Float.log(2); break;
622            case 3: c = 1/Float.log(2); break;
623            case 4: c = 1/Float.log(10); break;
624//            case 5: c = Float.atan(1) * 4; break;
625            case 6: c = Float.sqrt(0.5); break;
626            case 7: c = Float.sqrt(2); break;
627            }
628            if (p <= 1024) {
629                const_tab[n] = { prec: p, val: c };
630            }
631            return c;
632        }
633    }
634
635    add_props(Float, {
636        isFloat(a) {
637            return typeof a === "number" || typeof a === "bigfloat";
638        },
639        bestappr(u, b) {
640            var num1, num0, den1, den0, u, num, den, n;
641
642            if (typeof b === "undefined")
643                throw TypeError("second argument expected");
644            num1 = 1;
645            num0 = 0;
646            den1 = 0;
647            den0 = 1;
648            for(;;) {
649                n = Integer(Float.floor(u));
650                num = n * num1 + num0;
651                den = n * den1 + den0;
652                if (den > b)
653                    break;
654                u = 1.0 / (u - n);
655                num0 = num1;
656                num1 = num;
657                den0 = den1;
658                den1 = den;
659            }
660            return Fraction(num1, den1);
661        },
662        /* similar constants as Math.x */
663        get E() { return get_const(0); },
664        get LN10() { return get_const(1); },
665//        get LN2() { return get_const(2); },
666        get LOG2E() { return get_const(3); },
667        get LOG10E() { return get_const(4); },
668//        get PI() { return get_const(5); },
669        get SQRT1_2() { return get_const(6); },
670        get SQRT2() { return get_const(7); },
671    });
672
673    add_props(Float.prototype, {
674        inverse() {
675            return 1.0 / this;
676        },
677        norm2() {
678            return this * this;
679        },
680        abs() {
681            return Float.abs(this);
682        },
683        conj() {
684            return this;
685        },
686        arg() {
687            if (this >= 0)
688                return 0;
689            else
690                return Float.PI;
691        },
692        exp() {
693            return Float.exp(this);
694        },
695        log() {
696            if (this < 0) {
697                return Complex(this).log();
698            } else {
699                return Float.log(this);
700            }
701        },
702    });
703
704    /* Complex */
705
706    Complex = function Complex(re, im)
707    {
708        var obj;
709        if (new.target)
710            throw TypeError("not a constructor");
711        if (re instanceof Complex)
712            return re;
713        if (typeof im === "undefined") {
714            im = 0;
715        }
716        obj = Object.create(Complex.prototype);
717        obj.re = re;
718        obj.im = im;
719        return obj;
720    }
721
722
723    function complex_add(a, b) {
724        a = Complex(a);
725        b = Complex(b);
726        return Complex.toComplex(a.re + b.re, a.im + b.im);
727    }
728    function complex_sub(a, b) {
729        a = Complex(a);
730        b = Complex(b);
731        return Complex.toComplex(a.re - b.re, a.im - b.im);
732    }
733    function complex_mul(a, b) {
734        a = Complex(a);
735        b = Complex(b);
736        return Complex.toComplex(a.re * b.re - a.im * b.im,
737                                 a.re * b.im + a.im * b.re);
738    }
739    function complex_div(a, b) {
740        a = Complex(a);
741        b = Complex(b);
742        return a * b.inverse();
743    }
744    function complex_eq(a, b) {
745        a = Complex(a);
746        b = Complex(b);
747        return a.re == b.re && a.im == b.im;
748    }
749
750    operators_set(Complex.prototype,
751        {
752            "+": complex_add,
753            "-": complex_sub,
754            "*": complex_mul,
755            "/": complex_div,
756            "**": generic_pow,
757            "==": complex_eq,
758            "pos"(a) {
759                return a;
760            },
761            "neg"(a) {
762                return Complex(-a.re, -a.im);
763            }
764        },
765        {
766            left: [Number, BigInt, Float, Fraction],
767            right: [Number, BigInt, Float, Fraction],
768            "+": complex_add,
769            "-": complex_sub,
770            "*": complex_mul,
771            "/": complex_div,
772            "**": generic_pow,
773            "==": complex_eq,
774        });
775
776    add_props(Complex, {
777        /* simplify to real number when possible */
778        toComplex(re, im) {
779            if (algebraicMode && im == 0)
780                return re;
781            else
782                return Complex(re, im);
783        },
784    });
785
786    add_props(Complex.prototype, {
787        inverse() {
788            var c = this.norm2();
789            return Complex(this.re / c, -this.im / c);
790        },
791        toString() {
792            var v, s = "", a = this;
793            if (a.re != 0)
794                s += a.re.toString();
795            if (a.im == 1) {
796                if (s != "")
797                    s += "+";
798                s += "I";
799            } else if (a.im == -1) {
800                s += "-I";
801            } else {
802                v = a.im.toString();
803                if (v[0] != "-" && s != "")
804                    s += "+";
805                s += v + "*I";
806            }
807            return s;
808        },
809        norm2() {
810            return this.re * this.re + this.im * this.im;
811        },
812        abs() {
813            return Float.sqrt(norm2(this));
814        },
815        conj() {
816            return Complex(this.re, -this.im);
817        },
818        arg() {
819            return Float.atan2(this.im, this.re);
820        },
821        exp() {
822            var arg = this.im, r = this.re.exp();
823            return Complex(r * cos(arg), r * sin(arg));
824        },
825        log() {
826            return Complex(abs(this).log(), atan2(this.im, this.re));
827        },
828    });
829
830    /* Mod */
831
832    Mod = function Mod(a, m) {
833        var obj, t;
834        if (new.target)
835            throw TypeError("not a constructor");
836        obj = Object.create(Mod.prototype);
837        if (Integer.isInteger(m)) {
838            if (m <= 0)
839                throw RangeError("the modulo cannot be <= 0");
840            if (Integer.isInteger(a)) {
841                a %= m;
842            } else if (a instanceof Fraction) {
843                return Mod(a.num, m) / a.den;
844            } else {
845                throw TypeError("invalid types");
846            }
847        } else {
848            throw TypeError("invalid types");
849        }
850        obj.res = a;
851        obj.mod = m;
852        return obj;
853    };
854
855    function mod_add(a, b) {
856        if (!(a instanceof Mod)) {
857            return Mod(a + b.res, b.mod);
858        } else if (!(b instanceof Mod)) {
859            return Mod(a.res + b, a.mod);
860        } else {
861            if (a.mod != b.mod)
862                throw TypeError("different modulo for binary operator");
863            return Mod(a.res + b.res, a.mod);
864        }
865    }
866    function mod_sub(a, b) {
867        if (!(a instanceof Mod)) {
868            return Mod(a - b.res, b.mod);
869        } else if (!(b instanceof Mod)) {
870            return Mod(a.res - b, a.mod);
871        } else {
872            if (a.mod != b.mod)
873                throw TypeError("different modulo for binary operator");
874            return Mod(a.res - b.res, a.mod);
875        }
876    }
877    function mod_mul(a, b) {
878        if (!(a instanceof Mod)) {
879            return Mod(a * b.res, b.mod);
880        } else if (!(b instanceof Mod)) {
881            return Mod(a.res * b, a.mod);
882        } else {
883            if (a.mod != b.mod)
884                throw TypeError("different modulo for binary operator");
885            return Mod(a.res * b.res, a.mod);
886        }
887    }
888    function mod_div(a, b) {
889        if (!(b instanceof Mod))
890            b = Mod(b, a.mod);
891        return mod_mul(a, b.inverse());
892    }
893    function mod_eq(a, b) {
894        return (a.mod == b.mod && a.res == b.res);
895    }
896
897    operators_set(Mod.prototype,
898        {
899            "+": mod_add,
900            "-": mod_sub,
901            "*": mod_mul,
902            "/": mod_div,
903            "**": generic_pow,
904            "==": mod_eq,
905            "pos"(a) {
906                return a;
907            },
908            "neg"(a) {
909                return Mod(-a.res, a.mod);
910            }
911        },
912        {
913            left: [Number, BigInt, Float, Fraction],
914            right: [Number, BigInt, Float, Fraction],
915            "+": mod_add,
916            "-": mod_sub,
917            "*": mod_mul,
918            "/": mod_div,
919            "**": generic_pow,
920        });
921
922    add_props(Mod.prototype, {
923        inverse() {
924            var a = this, m = a.mod;
925            if (Integer.isInteger(m)) {
926                return Mod(Integer.invmod(a.res, m), m);
927            } else {
928                throw TypeError("unsupported type");
929            }
930        },
931        toString() {
932            return "Mod(" + this.res + "," + this.mod + ")";
933        },
934    });
935
936    /* Polynomial */
937
938    function polynomial_is_scalar(a)
939    {
940        if (typeof a === "number" ||
941            typeof a === "bigint" ||
942            typeof a === "bigfloat")
943            return true;
944        if (a instanceof Fraction ||
945            a instanceof Complex ||
946            a instanceof Mod)
947            return true;
948        return false;
949    }
950
951    Polynomial = function Polynomial(a)
952    {
953        if (new.target)
954            throw TypeError("not a constructor");
955        if (a instanceof Polynomial) {
956            return a;
957        } else if (Array.isArray(a)) {
958            if (a.length == 0)
959                a = [ 0 ];
960            Object.setPrototypeOf(a, Polynomial.prototype);
961            return a.trim();
962        } else if (polynomial_is_scalar(a)) {
963            a = [a];
964            Object.setPrototypeOf(a, Polynomial.prototype);
965            return a;
966        } else {
967            throw TypeError("invalid type");
968        }
969    }
970
971    function number_need_paren(c)
972    {
973        return !(Integer.isInteger(c) ||
974                 Float.isFloat(c) ||
975                 c instanceof Fraction ||
976                 (c instanceof Complex && c.re == 0));
977    }
978
979    /* string for c*X^i */
980    function monomial_toString(c, i)
981    {
982        var str1;
983        if (i == 0) {
984            str1 = c.toString();
985        } else {
986            if (c == 1) {
987                str1 = "";
988            } else if (c == -1) {
989                str1 = "-";
990            } else {
991                if (number_need_paren(c)) {
992                    str1 = "(" + c + ")";
993                } else {
994                    str1 = String(c);
995                }
996                str1 += "*";
997            }
998            str1 += "X";
999            if (i != 1) {
1000                str1 += "^" + i;
1001            }
1002        }
1003        return str1;
1004    }
1005
1006    /* find one complex root of 'p' starting from z at precision eps using
1007       at most max_it iterations. Return null if could not find root. */
1008    function poly_root_laguerre1(p, z, max_it)
1009    {
1010        var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl;
1011
1012        d = p.deg();
1013        if (d == 1) {
1014            /* monomial case */
1015            return -p[0] / p[1];
1016        }
1017        /* trivial zero */
1018        if (p[0] == 0)
1019            return 0.0;
1020
1021        p1 = p.deriv();
1022        p2 = p1.deriv();
1023        el = 0.0;
1024        zl = 0.0;
1025        for(i = 0; i < max_it; i++) {
1026            z0 = p.apply(z);
1027            if (z0 == 0)
1028                return z; /* simple exit case */
1029
1030            /* Ward stopping criteria */
1031            e = abs(z - zl);
1032//            print("e", i, e);
1033            if (i >= 2 && e >= el) {
1034                if (abs(zl) < 1e-4) {
1035                    if (e < 1e-7)
1036                        return zl;
1037                } else {
1038                    if (e < abs(zl) * 1e-3)
1039                        return zl;
1040                }
1041            }
1042            el = e;
1043            zl = z;
1044
1045            z1 = p1.apply(z);
1046            z2 = p2.apply(z);
1047            t0 = (d - 1) * z1;
1048            t0 = t0 * t0;
1049            t1 = d * (d - 1) * z0 * z2;
1050            t0 = sqrt(t0 - t1);
1051            d1 = z1 + t0;
1052            d2 = z1 - t0;
1053            if (norm2(d2) > norm2(d1))
1054                d1 = d2;
1055            if (d1 == 0)
1056                return null;
1057            z = z - d * z0 / d1;
1058        }
1059        return null;
1060    }
1061
1062    function poly_roots(p)
1063    {
1064        var d, i, roots, j, z, eps;
1065        var start_points = [ 0.1, -1.4, 1.7 ];
1066
1067        if (!(p instanceof Polynomial))
1068            throw TypeError("polynomial expected");
1069        d = p.deg();
1070        if (d <= 0)
1071            return [];
1072        eps = 2.0 ^ (-BigFloatEnv.prec);
1073        roots = [];
1074        for(i = 0; i < d; i++) {
1075            /* XXX: should select another start point if error */
1076            for(j = 0; j < 3; j++) {
1077                z = poly_root_laguerre1(p, start_points[j], 100);
1078                if (z !== null)
1079                    break;
1080            }
1081            if (j == 3)
1082                throw RangeError("error in root finding algorithm");
1083            roots[i] = z;
1084            p = Polynomial.divrem(p, X - z)[0];
1085        }
1086        return roots;
1087    }
1088
1089    add_props(Polynomial.prototype, {
1090        trim() {
1091            var a = this, i;
1092            i = a.length;
1093            while (i > 1 && a[i - 1] == 0)
1094                i--;
1095            a.length = i;
1096            return a;
1097        },
1098        conj() {
1099            var r, i, n, a;
1100            a = this;
1101            n = a.length;
1102            r = [];
1103            for(i = 0; i < n; i++)
1104                r[i] = a[i].conj();
1105            return Polynomial(r);
1106        },
1107        inverse() {
1108            return RationalFunction(Polynomial([1]), this);
1109        },
1110        toString() {
1111            var i, str, str1, c, a = this;
1112            if (a.length == 1) {
1113                return a[0].toString();
1114            }
1115            str="";
1116            for(i = a.length - 1; i >= 0; i--) {
1117                c = a[i];
1118                if (c == 0 ||
1119                    (c instanceof Mod) && c.res == 0)
1120                    continue;
1121                str1 = monomial_toString(c, i);
1122                if (str1[0] != "-") {
1123                    if (str != "")
1124                        str += "+";
1125                }
1126                str += str1;
1127            }
1128            return str;
1129        },
1130        deg() {
1131            if (this.length == 1 && this[0] == 0)
1132                return -Infinity;
1133            else
1134                return this.length - 1;
1135        },
1136        apply(b) {
1137            var i, n, r, a = this;
1138            n = a.length - 1;
1139            r = a[n];
1140            while (n > 0) {
1141                n--;
1142                r = r * b + a[n];
1143            }
1144            return r;
1145        },
1146        deriv() {
1147            var a = this, n, r, i;
1148            n = a.length;
1149            if (n == 1) {
1150                return Polynomial(0);
1151            } else {
1152                r = [];
1153                for(i = 1; i < n; i++) {
1154                    r[i - 1] = i * a[i];
1155                }
1156                return Polynomial(r);
1157            }
1158        },
1159        integ() {
1160            var a = this, n, r, i;
1161            n = a.length;
1162            r = [0];
1163            for(i = 0; i < n; i++) {
1164                r[i + 1] = a[i] / (i + 1);
1165            }
1166            return Polynomial(r);
1167        },
1168        norm2() {
1169            var a = this, n, r, i;
1170            n = a.length;
1171            r = 0;
1172            for(i = 0; i < n; i++) {
1173                r += a[i].norm2();
1174            }
1175            return r;
1176        },
1177    });
1178
1179
1180    function polynomial_add(a, b) {
1181        var tmp, r, i, n1, n2;
1182        a = Polynomial(a);
1183        b = Polynomial(b);
1184        if (a.length < b.length) {
1185            tmp = a;
1186            a = b;
1187            b = tmp;
1188        }
1189        n1 = b.length;
1190        n2 = a.length;
1191        r = [];
1192        for(i = 0; i < n1; i++)
1193            r[i] = a[i] + b[i];
1194        for(i = n1; i < n2; i++)
1195            r[i] = a[i];
1196        return Polynomial(r);
1197    }
1198    function polynomial_sub(a, b) {
1199        return polynomial_add(a, -b);
1200    }
1201    function polynomial_mul(a, b) {
1202        var i, j, n1, n2, n, r;
1203        a = Polynomial(a);
1204        b = Polynomial(b);
1205        n1 = a.length;
1206        n2 = b.length;
1207        n = n1 + n2 - 1;
1208        r = [];
1209        for(i = 0; i < n; i++)
1210            r[i] = 0;
1211        for(i = 0; i < n1; i++) {
1212            for(j = 0; j < n2; j++) {
1213                r[i + j] += a[i] * b[j];
1214            }
1215        }
1216        return Polynomial(r);
1217    }
1218    function polynomial_div_scalar(a, b) {
1219        return a * (1 / b);
1220    }
1221    function polynomial_div(a, b)
1222    {
1223        return RationalFunction(Polynomial(a),
1224                                Polynomial(b));
1225    }
1226    function polynomial_mod(a, b) {
1227        return Polynomial.divrem(a, b)[1];
1228    }
1229    function polynomial_eq(a, b) {
1230        var n, i;
1231        n = a.length;
1232        if (n != b.length)
1233            return false;
1234        for(i = 0; i < n; i++) {
1235            if (a[i] != b[i])
1236                return false;
1237        }
1238        return true;
1239    }
1240
1241    operators_set(Polynomial.prototype,
1242        {
1243            "+": polynomial_add,
1244            "-": polynomial_sub,
1245            "*": polynomial_mul,
1246            "/": polynomial_div,
1247            "**": generic_pow,
1248            "==": polynomial_eq,
1249            "pos"(a) {
1250                return a;
1251            },
1252            "neg"(a) {
1253                var r, i, n, a;
1254                n = a.length;
1255                r = [];
1256                for(i = 0; i < n; i++)
1257                r[i] = -a[i];
1258                return Polynomial(r);
1259            },
1260        },
1261        {
1262            left: [Number, BigInt, Float, Fraction, Complex, Mod],
1263            "+": polynomial_add,
1264            "-": polynomial_sub,
1265            "*": polynomial_mul,
1266            "/": polynomial_div,
1267            "**": generic_pow, /* XXX: only for integer */
1268        },
1269        {
1270            right: [Number, BigInt, Float, Fraction, Complex, Mod],
1271            "+": polynomial_add,
1272            "-": polynomial_sub,
1273            "*": polynomial_mul,
1274            "/": polynomial_div_scalar,
1275            "**": generic_pow, /* XXX: only for integer */
1276        });
1277
1278    add_props(Polynomial, {
1279        divrem(a, b) {
1280            var n1, n2, i, j, q, r, n, c;
1281            if (b.deg() < 0)
1282                throw RangeError("division by zero");
1283            n1 = a.length;
1284            n2 = b.length;
1285            if (n1 < n2)
1286                return [Polynomial([0]), a];
1287            r = Array.prototype.dup.call(a);
1288            q = [];
1289            n2--;
1290            n = n1 - n2;
1291            for(i = 0; i < n; i++)
1292                q[i] = 0;
1293            for(i = n - 1; i >= 0; i--) {
1294                c = r[i + n2];
1295                if (c != 0) {
1296                    c = c / b[n2];
1297                    r[i + n2] = 0;
1298                    for(j = 0; j < n2; j++) {
1299                        r[i + j] -= b[j] * c;
1300                    }
1301                    q[i] = c;
1302                }
1303            }
1304            return [Polynomial(q), Polynomial(r)];
1305        },
1306        gcd(a, b) {
1307            var t;
1308            while (b.deg() >= 0) {
1309                t = Polynomial.divrem(a, b);
1310                a = b;
1311                b = t[1];
1312            }
1313            /* convert to monic form */
1314            return a / a[a.length - 1];
1315        },
1316        invmod(x, y) {
1317            var q, u, v, a, c, t;
1318            u = x;
1319            v = y;
1320            c = Polynomial([1]);
1321            a = Polynomial([0]);
1322            while (u.deg() >= 0) {
1323                t = Polynomial.divrem(v, u);
1324                q = t[0];
1325                v = u;
1326                u = t[1];
1327                t = c;
1328                c = a - q * c;
1329                a = t;
1330            }
1331            /* v = gcd(x, y) */
1332            if (v.deg() > 0)
1333                throw RangeError("not invertible");
1334            return Polynomial.divrem(a, y)[1];
1335        },
1336        roots(p) {
1337            return poly_roots(p);
1338        }
1339    });
1340
1341    /* Polynomial Modulo Q */
1342
1343    PolyMod = function PolyMod(a, m) {
1344        var obj, t;
1345        if (new.target)
1346            throw TypeError("not a constructor");
1347        obj = Object.create(PolyMod.prototype);
1348        if (m instanceof Polynomial) {
1349            if (m.deg() <= 0)
1350                throw RangeError("the modulo cannot have a degree <= 0");
1351            if (a instanceof RationalFunction) {
1352                return PolyMod(a.num, m) / a.den;
1353            } else {
1354                a = Polynomial(a);
1355                t = Polynomial.divrem(a, m);
1356                a = t[1];
1357            }
1358        } else {
1359            throw TypeError("invalid types");
1360        }
1361        obj.res = a;
1362        obj.mod = m;
1363        return obj;
1364    };
1365
1366    function polymod_add(a, b) {
1367        if (!(a instanceof PolyMod)) {
1368            return PolyMod(a + b.res, b.mod);
1369        } else if (!(b instanceof PolyMod)) {
1370            return PolyMod(a.res + b, a.mod);
1371        } else {
1372            if (a.mod != b.mod)
1373                throw TypeError("different modulo for binary operator");
1374            return PolyMod(a.res + b.res, a.mod);
1375        }
1376    }
1377    function polymod_sub(a, b) {
1378        return polymod_add(a, -b);
1379    }
1380    function polymod_mul(a, b) {
1381        if (!(a instanceof PolyMod)) {
1382            return PolyMod(a * b.res, b.mod);
1383        } else if (!(b instanceof PolyMod)) {
1384            return PolyMod(a.res * b, a.mod);
1385        } else {
1386            if (a.mod != b.mod)
1387                    throw TypeError("different modulo for binary operator");
1388            return PolyMod(a.res * b.res, a.mod);
1389        }
1390    }
1391    function polymod_div(a, b) {
1392        if (!(b instanceof PolyMod))
1393            b = PolyMod(b, a.mod);
1394        return polymod_mul(a, b.inverse());
1395    }
1396    function polymod_eq(a, b) {
1397        return (a.mod == b.mod && a.res == b.res);
1398    }
1399
1400    operators_set(PolyMod.prototype,
1401        {
1402            "+": polymod_add,
1403            "-": polymod_sub,
1404            "*": polymod_mul,
1405            "/": polymod_div,
1406            "**": generic_pow,
1407            "==": polymod_eq,
1408            "pos"(a) {
1409                return a;
1410            },
1411            "neg"(a) {
1412                return PolyMod(-a.res, a.mod);
1413            },
1414        },
1415        {
1416            left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1417            right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1418            "+": polymod_add,
1419            "-": polymod_sub,
1420            "*": polymod_mul,
1421            "/": polymod_div,
1422            "**": generic_pow, /* XXX: only for integer */
1423        });
1424
1425    add_props(PolyMod.prototype, {
1426        inverse() {
1427            var a = this, m = a.mod;
1428            if (m instanceof Polynomial) {
1429                return PolyMod(Polynomial.invmod(a.res, m), m);
1430            } else {
1431                throw TypeError("unsupported type");
1432            }
1433        },
1434        toString() {
1435            return "PolyMod(" + this.res + "," + this.mod + ")";
1436        },
1437    });
1438
1439    /* Rational function */
1440
1441    RationalFunction = function RationalFunction(a, b)
1442    {
1443        var t, r, d, obj;
1444        if (new.target)
1445            throw TypeError("not a constructor");
1446        if (!(a instanceof Polynomial) ||
1447            !(b instanceof Polynomial))
1448            throw TypeError("polynomial expected");
1449        t = Polynomial.divrem(a, b);
1450        r = t[1];
1451        if (r.deg() < 0)
1452            return t[0]; /* no need for a fraction */
1453        d = Polynomial.gcd(b, r);
1454        if (d.deg() > 0) {
1455            a = Polynomial.divrem(a, d)[0];
1456            b = Polynomial.divrem(b, d)[0];
1457        }
1458        obj = Object.create(RationalFunction.prototype);
1459        obj.num = a;
1460        obj.den = b;
1461        return obj;
1462    }
1463
1464    add_props(RationalFunction.prototype, {
1465        inverse() {
1466            return RationalFunction(this.den, this.num);
1467        },
1468        conj() {
1469            return RationalFunction(this.num.conj(), this.den.conj());
1470        },
1471        toString() {
1472            var str;
1473            if (this.num.deg() <= 0 &&
1474                !number_need_paren(this.num[0]))
1475                str = this.num.toString();
1476            else
1477                str = "(" + this.num.toString() + ")";
1478            str += "/(" + this.den.toString() + ")"
1479            return str;
1480        },
1481        apply(b) {
1482            return this.num.apply(b) / this.den.apply(b);
1483        },
1484        deriv() {
1485            var n = this.num, d = this.den;
1486            return RationalFunction(n.deriv() * d - n * d.deriv(), d * d);
1487        },
1488    });
1489
1490    function ratfunc_add(a, b) {
1491        a = RationalFunction.toRationalFunction(a);
1492        b = RationalFunction.toRationalFunction(b);
1493        return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den);
1494    }
1495    function ratfunc_sub(a, b) {
1496        a = RationalFunction.toRationalFunction(a);
1497        b = RationalFunction.toRationalFunction(b);
1498        return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den);
1499    }
1500    function ratfunc_mul(a, b) {
1501        a = RationalFunction.toRationalFunction(a);
1502        b = RationalFunction.toRationalFunction(b);
1503        return RationalFunction(a.num * b.num, a.den * b.den);
1504    }
1505    function ratfunc_div(a, b) {
1506        a = RationalFunction.toRationalFunction(a);
1507        b = RationalFunction.toRationalFunction(b);
1508        return RationalFunction(a.num * b.den, a.den * b.num);
1509    }
1510    function ratfunc_eq(a, b) {
1511        a = RationalFunction.toRationalFunction(a);
1512        b = RationalFunction.toRationalFunction(b);
1513        /* we assume the fractions are normalized */
1514        return (a.num == b.num && a.den == b.den);
1515    }
1516
1517    operators_set(RationalFunction.prototype,
1518        {
1519            "+": ratfunc_add,
1520            "-": ratfunc_sub,
1521            "*": ratfunc_mul,
1522            "/": ratfunc_div,
1523            "**": generic_pow,
1524            "==": ratfunc_eq,
1525            "pos"(a) {
1526                return a;
1527            },
1528            "neg"(a) {
1529                return RationalFunction(-this.num, this.den);
1530            },
1531        },
1532        {
1533            left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1534            right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1535            "+": ratfunc_add,
1536            "-": ratfunc_sub,
1537            "*": ratfunc_mul,
1538            "/": ratfunc_div,
1539            "**": generic_pow, /* should only be used with integers */
1540        });
1541
1542    add_props(RationalFunction, {
1543        /* This function always return a RationalFunction object even
1544           if it could simplified to a polynomial, so it is not
1545           equivalent to RationalFunction(a) */
1546        toRationalFunction(a) {
1547            var obj;
1548            if (a instanceof RationalFunction) {
1549                return a;
1550            } else {
1551                obj = Object.create(RationalFunction.prototype);
1552                obj.num = Polynomial(a);
1553                obj.den = Polynomial(1);
1554                return obj;
1555            }
1556        },
1557    });
1558
1559    /* Power series */
1560
1561    /* 'a' is an array */
1562    function get_emin(a) {
1563        var i, n;
1564        n = a.length;
1565        for(i = 0; i < n; i++) {
1566            if (a[i] != 0)
1567                return i;
1568        }
1569        return n;
1570    };
1571
1572    function series_is_scalar_or_polynomial(a)
1573    {
1574        return polynomial_is_scalar(a) ||
1575            (a instanceof Polynomial);
1576    }
1577
1578    /* n is the maximum number of terms if 'a' is not a serie */
1579    Series = function Series(a, n) {
1580        var emin, r, i;
1581
1582        if (a instanceof Series) {
1583            return a;
1584        } else if (series_is_scalar_or_polynomial(a)) {
1585            if (n <= 0) {
1586                /* XXX: should still use the polynomial degree */
1587                return Series.zero(0, 0);
1588            } else {
1589                a = Polynomial(a);
1590                emin = get_emin(a);
1591                r = Series.zero(n, emin);
1592                n = Math.min(a.length - emin, n);
1593                for(i = 0; i < n; i++)
1594                    r[i] = a[i + emin];
1595                return r;
1596            }
1597        } else if (a instanceof RationalFunction) {
1598            return Series(a.num, n) / a.den;
1599        } else {
1600            throw TypeError("invalid type");
1601        }
1602    };
1603
1604    function series_add(v1, v2) {
1605        var tmp, d, emin, n, r, i, j, v2_emin, c1, c2;
1606        if (!(v1 instanceof Series)) {
1607            tmp = v1;
1608            v1 = v2;
1609            v2 = tmp;
1610        }
1611        d = v1.emin + v1.length;
1612        if (series_is_scalar_or_polynomial(v2)) {
1613            v2 = Polynomial(v2);
1614            if (d <= 0)
1615                return v1;
1616            v2_emin = 0;
1617        } else if (v2 instanceof RationalFunction) {
1618            /* compute the emin of the rational fonction */
1619            i = get_emin(v2.num) - get_emin(v2.den);
1620            if (d <= i)
1621                return v1;
1622            /* compute the serie with the required terms */
1623            v2 = Series(v2, d - i);
1624            v2_emin = v2.emin;
1625        } else {
1626            v2_emin = v2.emin;
1627            d = Math.min(d, v2_emin + v2.length);
1628        }
1629        emin = Math.min(v1.emin, v2_emin);
1630        n = d - emin;
1631        r = Series.zero(n, emin);
1632        /* XXX: slow */
1633        for(i = emin; i < d; i++) {
1634            j = i - v1.emin;
1635            if (j >= 0 && j < v1.length)
1636                c1 = v1[j];
1637            else
1638                c1 = 0;
1639            j = i - v2_emin;
1640            if (j >= 0 && j < v2.length)
1641                c2 = v2[j];
1642            else
1643                c2 = 0;
1644            r[i - emin] = c1 + c2;
1645        }
1646        return r.trim();
1647    }
1648    function series_sub(a, b) {
1649        return series_add(a, -b);
1650    }
1651    function series_mul(v1, v2) {
1652        var n, i, j, r, n, emin, n1, n2, k;
1653        if (!(v1 instanceof Series))
1654            v1 = Series(v1, v2.length);
1655        else if (!(v2 instanceof Series))
1656            v2 = Series(v2, v1.length);
1657        emin = v1.emin + v2.emin;
1658        n = Math.min(v1.length, v2.length);
1659        n1 = v1.length;
1660        n2 = v2.length;
1661        r = Series.zero(n, emin);
1662        for(i = 0; i < n1; i++) {
1663            k = Math.min(n2, n - i);
1664            for(j = 0; j < k; j++) {
1665                r[i + j] += v1[i] * v2[j];
1666            }
1667        }
1668        return r.trim();
1669    }
1670    function series_div(v1, v2) {
1671        if (!(v2 instanceof Series))
1672            v2 = Series(v2, v1.length);
1673        return series_mul(v1, v2.inverse());
1674    }
1675    function series_pow(a, b) {
1676        if (Integer.isInteger(b)) {
1677            return generic_pow(a, b);
1678        } else {
1679            if (!(a instanceof Series))
1680                a = Series(a, b.length);
1681            return exp(log(a) * b);
1682        }
1683    }
1684    function series_eq(a, b) {
1685        var n, i;
1686        if (a.emin != b.emin)
1687            return false;
1688        n = a.length;
1689        if (n != b.length)
1690            return false;
1691        for(i = 0; i < n; i++) {
1692            if (a[i] != b[i])
1693                return false;
1694        }
1695        return true;
1696    }
1697
1698    operators_set(Series.prototype,
1699        {
1700            "+": series_add,
1701            "-": series_sub,
1702            "*": series_mul,
1703            "/": series_div,
1704            "**": series_pow,
1705            "==": series_eq,
1706            "pos"(a) {
1707                return a;
1708            },
1709            "neg"(a) {
1710                var obj, n, i;
1711                n = a.length;
1712                obj = Series.zero(a.length, a.emin);
1713                for(i = 0; i < n; i++) {
1714                    obj[i] = -a[i];
1715                }
1716                return obj;
1717            },
1718        },
1719        {
1720            left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1721            right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial],
1722            "+": series_add,
1723            "-": series_sub,
1724            "*": series_mul,
1725            "/": series_div,
1726            "**": series_pow,
1727        });
1728
1729    add_props(Series.prototype, {
1730        conj() {
1731            var obj, n, i;
1732            n = this.length;
1733            obj = Series.zero(this.length, this.emin);
1734            for(i = 0; i < n; i++) {
1735                obj[i] = this[i].conj();
1736            }
1737            return obj;
1738        },
1739        inverse() {
1740            var r, n, i, j, sum, v1 = this;
1741            n = v1.length;
1742            if (n == 0)
1743                throw RangeError("division by zero");
1744            r = Series.zero(n, -v1.emin);
1745            r[0] = 1 / v1[0];
1746            for(i = 1; i < n; i++) {
1747                sum = 0;
1748                for(j = 1; j <= i; j++) {
1749                    sum += v1[j] * r[i - j];
1750                }
1751                r[i] = -sum * r[0];
1752            }
1753            return r;
1754        },
1755        /* remove leading zero terms */
1756        trim() {
1757            var i, j, n, r, v1 = this;
1758            n = v1.length;
1759            i = 0;
1760            while (i < n && v1[i] == 0)
1761                i++;
1762            if (i == 0)
1763                return v1;
1764            for(j = i; j < n; j++)
1765                v1[j - i] = v1[j];
1766            v1.length = n - i;
1767            v1.__proto__.emin += i;
1768            return v1;
1769        },
1770        toString() {
1771            var i, j, str, str1, c, a = this, emin, n;
1772            str="";
1773            emin = this.emin;
1774            n = this.length;
1775            for(j = 0; j < n; j++) {
1776                i = j + emin;
1777                c = a[j];
1778                if (c != 0) {
1779                    str1 = monomial_toString(c, i);
1780                    if (str1[0] != "-") {
1781                        if (str != "")
1782                            str += "+";
1783                    }
1784                    str += str1;
1785                }
1786            }
1787            if (str != "")
1788                str += "+";
1789            str += "O(" + monomial_toString(1, n + emin) + ")";
1790            return str;
1791        },
1792        apply(b) {
1793            var i, n, r, a = this;
1794            n = a.length;
1795            if (n == 0)
1796                return 0;
1797            r = a[--n];
1798            while (n > 0) {
1799                n--;
1800                r = r * b + a[n];
1801            }
1802            if (a.emin != 0)
1803                r *= b ^ a.emin;
1804            return r;
1805        },
1806        deriv() {
1807            var a = this, n = a.length, emin = a.emin, r, i, j;
1808            if (n == 0 && emin == 0) {
1809                return Series.zero(0, 0);
1810            } else {
1811                r = Series.zero(n, emin - 1);
1812                for(i = 0; i < n; i++) {
1813                    j = emin + i;
1814                    if (j == 0)
1815                        r[i] = 0;
1816                    else
1817                        r[i] = j * a[i];
1818                }
1819                return r.trim();
1820            }
1821        },
1822        integ() {
1823            var a = this, n = a.length, emin = a.emin, i, j, r;
1824            r = Series.zero(n, emin + 1);
1825            for(i = 0; i < n; i++) {
1826                j = emin + i;
1827                if (j == -1) {
1828                    if (a[i] != 0)
1829                        throw RangError("cannot represent integ(1/X)");
1830                } else {
1831                    r[i] = a[i] / (j + 1);
1832                }
1833            }
1834            return r.trim();
1835        },
1836        exp() {
1837            var c, i, r, n, a = this;
1838            if (a.emin < 0)
1839                throw RangeError("negative exponent in exp");
1840            n = a.emin + a.length;
1841            if (a.emin > 0 || a[0] == 0) {
1842                c = 1;
1843            } else {
1844                c = global.exp(a[0]);
1845                a -= a[0];
1846            }
1847            r = Series.zero(n, 0);
1848            for(i = 0; i < n; i++) {
1849                r[i] = c / fact(i);
1850            }
1851            return r.apply(a);
1852        },
1853        log() {
1854            var a = this, r;
1855            if (a.emin != 0)
1856                throw Range("log argument must have a non zero constant term");
1857            r = integ(deriv(a) / a);
1858            /* add the constant term */
1859            r += global.log(a[0]);
1860            return r;
1861        },
1862    });
1863
1864    add_props(Series, {
1865        /* new series of length n and first exponent emin */
1866        zero(n, emin) {
1867            var r, i, obj;
1868
1869            r = [];
1870            for(i = 0; i < n; i++)
1871                r[i] = 0;
1872            /* we return an array and store emin in its prototype */
1873            obj = Object.create(Series.prototype);
1874            obj.emin = emin;
1875            Object.setPrototypeOf(r, obj);
1876            return r;
1877        },
1878        O(a) {
1879            function ErrorO() {
1880                return TypeError("invalid O() argument");
1881            }
1882            var n;
1883            if (series_is_scalar_or_polynomial(a)) {
1884                a = Polynomial(a);
1885                n = a.deg();
1886                if (n < 0)
1887                    throw ErrorO();
1888            } else if (a instanceof RationalFunction) {
1889                if (a.num.deg() != 0)
1890                    throw ErrorO();
1891                n = a.den.deg();
1892                if (n < 0)
1893                    throw ErrorO();
1894                n = -n;
1895            } else
1896                throw ErrorO();
1897            return Series.zero(0, n);
1898        },
1899    });
1900
1901    /* Array (Matrix) */
1902
1903    Matrix = function Matrix(h, w) {
1904        var i, j, r, rl;
1905        if (typeof w === "undefined")
1906            w = h;
1907        r = [];
1908        for(i = 0; i < h; i++) {
1909            rl = [];
1910            for(j = 0; j < w; j++)
1911                rl[j] = 0;
1912            r[i] = rl;
1913        }
1914        return r;
1915    };
1916
1917    add_props(Matrix, {
1918        idn(n) {
1919            var r, i;
1920            r = Matrix(n, n);
1921            for(i = 0; i < n; i++)
1922                r[i][i] = 1;
1923            return r;
1924        },
1925        diag(a) {
1926            var r, i, n;
1927            n = a.length;
1928            r = Matrix(n, n);
1929            for(i = 0; i < n; i++)
1930                r[i][i] = a[i];
1931            return r;
1932        },
1933        hilbert(n) {
1934            var i, j, r;
1935            r = Matrix(n);
1936            for(i = 0; i < n; i++) {
1937                for(j = 0; j < n; j++) {
1938                    r[i][j] = 1 / (1 + i + j);
1939                }
1940            }
1941            return r;
1942        },
1943        trans(a) {
1944            var h, w, r, i, j;
1945            if (!Array.isArray(a))
1946                throw TypeError("matrix expected");
1947            h = a.length;
1948            if (!Array.isArray(a[0])) {
1949                w = 1;
1950                r = Matrix(w, h);
1951                for(i = 0; i < h; i++) {
1952                    r[0][i] = a[i];
1953                }
1954            } else {
1955                w = a[0].length;
1956                r = Matrix(w, h);
1957                for(i = 0; i < h; i++) {
1958                    for(j = 0; j < w; j++) {
1959                        r[j][i] = a[i][j];
1960                    }
1961                }
1962            }
1963            return r;
1964        },
1965        check_square(a) {
1966            var a, n;
1967            if (!Array.isArray(a))
1968                throw TypeError("array expected");
1969            n = a.length;
1970            if (!Array.isArray(a[0]) || n != a[0].length)
1971                throw TypeError("square matrix expected");
1972            return n;
1973        },
1974        trace(a) {
1975            var n, r, i;
1976            n = Matrix.check_square(a);
1977            r = a[0][0];
1978            for(i = 1; i < n; i++) {
1979                r += a[i][i];
1980            }
1981            return r;
1982        },
1983        charpoly(a) {
1984            var n, p, c, i, j, coef;
1985            n = Matrix.check_square(a);
1986            p = [];
1987            for(i = 0; i < n + 1; i++)
1988                p[i] = 0;
1989            p[n] = 1;
1990            c = Matrix.idn(n);
1991            for(i = 0; i < n; i++) {
1992                c = c * a;
1993                coef = -trace(c) / (i + 1);
1994                p[n - i - 1] = coef;
1995                for(j = 0; j < n; j++)
1996                    c[j][j] += coef;
1997            }
1998            return Polynomial(p);
1999        },
2000        eigenvals(a) {
2001            return Polynomial.roots(Matrix.charpoly(a));
2002        },
2003        det(a) {
2004            var n, i, j, k, s, src, v, c;
2005
2006            n = Matrix.check_square(a);
2007            s = 1;
2008            src = a.dup();
2009            for(i=0;i<n;i++) {
2010                for(j = i; j < n; j++) {
2011                    if (src[j][i] != 0)
2012                        break;
2013                }
2014                if (j == n)
2015                    return 0;
2016                if (j != i) {
2017                    for(k = 0;k < n; k++) {
2018                        v = src[j][k];
2019                        src[j][k] = src[i][k];
2020                        src[i][k] = v;
2021                    }
2022                    s = -s;
2023                }
2024                c = src[i][i].inverse();
2025                for(j = i + 1; j < n; j++) {
2026                    v = c * src[j][i];
2027                    for(k = 0;k < n; k++) {
2028                        src[j][k] -= src[i][k] * v;
2029                    }
2030                }
2031            }
2032            c = s;
2033            for(i=0;i<n;i++)
2034                c *= src[i][i];
2035            return c;
2036        },
2037        inverse(a) {
2038            var n, dst, src, i, j, k, n2, r, c, v;
2039            n = Matrix.check_square(a);
2040            src = a.dup();
2041            dst = Matrix.idn(n);
2042            for(i=0;i<n;i++) {
2043                for(j = i; j < n; j++) {
2044                    if (src[j][i] != 0)
2045                        break;
2046                }
2047                if (j == n)
2048                    throw RangeError("matrix is not invertible");
2049                if (j != i) {
2050                    /* swap lines in src and dst */
2051                    v = src[j];
2052                    src[j] = src[i];
2053                    src[i] = v;
2054                    v = dst[j];
2055                    dst[j] = dst[i];
2056                    dst[i] = v;
2057                }
2058
2059                c = src[i][i].inverse();
2060                for(k = 0; k < n; k++) {
2061                    src[i][k] *= c;
2062                    dst[i][k] *= c;
2063                }
2064
2065                for(j = 0; j < n; j++) {
2066                    if (j != i) {
2067                        c = src[j][i];
2068                        for(k = i; k < n; k++) {
2069                            src[j][k] -= src[i][k] * c;
2070                        }
2071                        for(k = 0; k < n; k++) {
2072                            dst[j][k] -= dst[i][k] * c;
2073                        }
2074                    }
2075                }
2076            }
2077            return dst;
2078        },
2079        rank(a) {
2080            var src, i, j, k, w, h, l, c;
2081
2082            if (!Array.isArray(a) ||
2083                !Array.isArray(a[0]))
2084                throw TypeError("matrix expected");
2085            h = a.length;
2086            w = a[0].length;
2087            src = a.dup();
2088            l = 0;
2089            for(i=0;i<w;i++) {
2090                for(j = l; j < h; j++) {
2091                    if (src[j][i] != 0)
2092                        break;
2093                }
2094                if (j == h)
2095                    continue;
2096                if (j != l) {
2097                    /* swap lines */
2098                    for(k = 0; k < w; k++) {
2099                        v = src[j][k];
2100                        src[j][k] = src[l][k];
2101                        src[l][k] = v;
2102                    }
2103                }
2104
2105                c = src[l][i].inverse();
2106                for(k = 0; k < w; k++) {
2107                    src[l][k] *= c;
2108                }
2109
2110                for(j = l + 1; j < h; j++) {
2111                    c = src[j][i];
2112                    for(k = i; k < w; k++) {
2113                        src[j][k] -= src[l][k] * c;
2114                    }
2115                }
2116                l++;
2117            }
2118            return l;
2119        },
2120        ker(a) {
2121            var src, i, j, k, w, h, l, m, r, im_cols, ker_dim, c;
2122
2123            if (!Array.isArray(a) ||
2124                !Array.isArray(a[0]))
2125                throw TypeError("matrix expected");
2126            h = a.length;
2127            w = a[0].length;
2128            src = a.dup();
2129            im_cols = [];
2130            l = 0;
2131            for(i=0;i<w;i++) {
2132                im_cols[i] = false;
2133                for(j = l; j < h; j++) {
2134                    if (src[j][i] != 0)
2135                        break;
2136                }
2137                if (j == h)
2138                    continue;
2139                im_cols[i] = true;
2140                if (j != l) {
2141                    /* swap lines */
2142                    for(k = 0; k < w; k++) {
2143                        v = src[j][k];
2144                        src[j][k] = src[l][k];
2145                        src[l][k] = v;
2146                    }
2147                }
2148
2149                c = src[l][i].inverse();
2150                for(k = 0; k < w; k++) {
2151                    src[l][k] *= c;
2152                }
2153
2154                for(j = 0; j < h; j++) {
2155                    if (j != l) {
2156                        c = src[j][i];
2157                        for(k = i; k < w; k++) {
2158                            src[j][k] -= src[l][k] * c;
2159                        }
2160                    }
2161                }
2162                l++;
2163                //        log_str("m=" + cval_toString(v1) + "\n");
2164            }
2165            //    log_str("im cols="+im_cols+"\n");
2166
2167            /* build the kernel vectors */
2168            ker_dim = w - l;
2169            r = Matrix(w, ker_dim);
2170            k = 0;
2171            for(i = 0; i < w; i++) {
2172                if (!im_cols[i]) {
2173                    /* select this column from the matrix */
2174                    l = 0;
2175                    m = 0;
2176                    for(j = 0; j < w; j++) {
2177                        if (im_cols[j]) {
2178                            r[j][k] = -src[m][i];
2179                            m++;
2180                        } else {
2181                            if (l == k) {
2182                                r[j][k] = 1;
2183                            } else {
2184                                r[j][k] = 0;
2185                            }
2186                            l++;
2187                        }
2188                    }
2189                    k++;
2190                }
2191            }
2192            return r;
2193        },
2194        dp(a, b) {
2195            var i, n, r;
2196            n = a.length;
2197            if (n != b.length)
2198                throw TypeError("incompatible array length");
2199            /* XXX: could do complex product */
2200            r = 0;
2201            for(i = 0; i < n; i++) {
2202                r += a[i] * b[i];
2203            }
2204            return r;
2205        },
2206        /* cross product */
2207        cp(v1, v2) {
2208            var r;
2209            if (v1.length != 3 || v2.length != 3)
2210                throw TypeError("vectors must have 3 elements");
2211            r = [];
2212            r[0] = v1[1] * v2[2] - v1[2] * v2[1];
2213            r[1] = v1[2] * v2[0] - v1[0] * v2[2];
2214            r[2] = v1[0] * v2[1] - v1[1] * v2[0];
2215            return r;
2216        },
2217    });
2218
2219    function array_add(a, b) {
2220        var r, i, n;
2221        n = a.length;
2222        if (n != b.length)
2223            throw TypeError("incompatible array size");
2224        r = [];
2225        for(i = 0; i < n; i++)
2226            r[i] = a[i] + b[i];
2227        return r;
2228    }
2229    function array_sub(a, b) {
2230        var r, i, n;
2231        n = a.length;
2232        if (n != b.length)
2233            throw TypeError("incompatible array size");
2234        r = [];
2235        for(i = 0; i < n; i++)
2236            r[i] = a[i] - b[i];
2237        return r;
2238    }
2239    function array_scalar_mul(a, b) {
2240        var r, i, n;
2241        n = a.length;
2242        r = [];
2243        for(i = 0; i < n; i++)
2244            r[i] = a[i] * b;
2245        return r;
2246    }
2247    function array_mul(a, b) {
2248        var h, w, l, i, j, k, r, rl, sum, a_mat, b_mat;
2249        h = a.length;
2250        a_mat = Array.isArray(a[0]);
2251        if (a_mat) {
2252            l = a[0].length;
2253        } else {
2254            l = 1;
2255        }
2256        if (l != b.length)
2257            throw RangeError("incompatible matrix size");
2258        b_mat = Array.isArray(b[0]);
2259        if (b_mat)
2260            w = b[0].length;
2261        else
2262            w = 1;
2263        r = [];
2264        if (a_mat && b_mat) {
2265            for(i = 0; i < h; i++) {
2266                rl = [];
2267                for(j = 0; j < w; j++) {
2268                    sum = 0;
2269                    for(k = 0; k < l; k++) {
2270                        sum += a[i][k] * b[k][j];
2271                    }
2272                    rl[j] = sum;
2273                }
2274                r[i] = rl;
2275            }
2276        } else if (a_mat && !b_mat) {
2277            for(i = 0; i < h; i++) {
2278                sum = 0;
2279                for(k = 0; k < l; k++) {
2280                    sum += a[i][k] * b[k];
2281                }
2282                r[i] = sum;
2283            }
2284        } else if (!a_mat && b_mat) {
2285            for(i = 0; i < h; i++) {
2286                rl = [];
2287                for(j = 0; j < w; j++) {
2288                    rl[j] = a[i] * b[0][j];
2289                }
2290                r[i] = rl;
2291            }
2292        } else {
2293            for(i = 0; i < h; i++) {
2294                r[i] = a[i] * b[0];
2295            }
2296        }
2297        return r;
2298    }
2299    function array_div(a, b) {
2300        return array_mul(a, b.inverse());
2301    }
2302    function array_scalar_div(a, b) {
2303        return a * b.inverse();
2304    }
2305    function array_eq(a, b) {
2306        var n, i;
2307        n = a.length;
2308        if (n != b.length)
2309            return false;
2310        for(i = 0; i < n; i++) {
2311            if (a[i] != b[i])
2312                return false;
2313        }
2314        return true;
2315    }
2316
2317    operators_set(Array.prototype,
2318        {
2319            "+": array_add,
2320            "-": array_sub,
2321            "*": array_mul,
2322            "/": array_div,
2323            "==": array_eq,
2324            "pos"(a) {
2325                return a;
2326            },
2327            "neg"(a) {
2328                var i, n, r;
2329                n = a.length;
2330                r = [];
2331                for(i = 0; i < n; i++)
2332                    r[i] = -a[i];
2333                return r;
2334            }
2335        },
2336        {
2337            right: [Number, BigInt, Float, Fraction, Complex, Mod,
2338                    Polynomial, PolyMod, RationalFunction, Series],
2339            "*": array_scalar_mul,
2340            "/": array_scalar_div,
2341            "**": generic_pow, /* XXX: only for integer */
2342        },
2343        {
2344            left: [Number, BigInt, Float, Fraction, Complex, Mod,
2345                   Polynomial, PolyMod, RationalFunction, Series],
2346            "*"(a, b) { return array_scalar_mul(b, a); },
2347            "/"(a, b) { return array_scalar_div(b, a); },
2348        });
2349
2350    add_props(Array.prototype, {
2351        conj() {
2352            var i, n, r;
2353            n = this.length;
2354            r = [];
2355            for(i = 0; i < n; i++)
2356                r[i] = this[i].conj();
2357            return r;
2358        },
2359        dup() {
2360            var r, i, n, el, a = this;
2361            r = [];
2362            n = a.length;
2363            for(i = 0; i < n; i++) {
2364                el = a[i];
2365                if (Array.isArray(el))
2366                    el = el.dup();
2367                r[i] = el;
2368            }
2369            return r;
2370        },
2371        inverse() {
2372            return Matrix.inverse(this);
2373        },
2374        norm2: Polynomial.prototype.norm2,
2375    });
2376
2377})(this);
2378
2379/* global definitions */
2380var I = Complex(0, 1);
2381var X = Polynomial([0, 1]);
2382var O = Series.O;
2383
2384Object.defineProperty(this, "PI", { get: function () { return Float.PI } });
2385
2386/* put frequently used functions in the global context */
2387var gcd = Integer.gcd;
2388var fact = Integer.fact;
2389var comb = Integer.comb;
2390var pmod = Integer.pmod;
2391var invmod = Integer.invmod;
2392var factor = Integer.factor;
2393var isprime = Integer.isPrime;
2394var nextprime = Integer.nextPrime;
2395
2396function deriv(a)
2397{
2398    return a.deriv();
2399}
2400
2401function integ(a)
2402{
2403    return a.integ();
2404}
2405
2406function norm2(a)
2407{
2408    return a.norm2();
2409}
2410
2411function abs(a)
2412{
2413    return a.abs();
2414}
2415
2416function conj(a)
2417{
2418    return a.conj();
2419}
2420
2421function arg(a)
2422{
2423    return a.arg();
2424}
2425
2426function inverse(a)
2427{
2428    return a.inverse();
2429}
2430
2431function trunc(a)
2432{
2433    if (Integer.isInteger(a)) {
2434        return a;
2435    } else if (a instanceof Fraction) {
2436        return Integer.tdiv(a.num, a.den);
2437    } else if (a instanceof Polynomial) {
2438        return a;
2439    } else if (a instanceof RationalFunction) {
2440        return Polynomial.divrem(a.num, a.den)[0];
2441    } else {
2442        return Float.ceil(a);
2443    }
2444}
2445
2446function floor(a)
2447{
2448    if (Integer.isInteger(a)) {
2449        return a;
2450    } else if (a instanceof Fraction) {
2451        return Integer.fdiv(a.num, a.den);
2452    } else {
2453        return Float.floor(a);
2454    }
2455}
2456
2457function ceil(a)
2458{
2459    if (Integer.isInteger(a)) {
2460        return a;
2461    } else if (a instanceof Fraction) {
2462        return Integer.cdiv(a.num, a.den);
2463    } else {
2464        return Float.ceil(a);
2465    }
2466}
2467
2468function sqrt(a)
2469{
2470    var t, u, re, im;
2471    if (a instanceof Series) {
2472        return a ^ (1/2);
2473    } else if (a instanceof Complex) {
2474        t = abs(a);
2475        u = a.re;
2476        re = sqrt((t + u) / 2);
2477        im = sqrt((t - u) / 2);
2478        if (a.im < 0)
2479            im = -im;
2480        return Complex.toComplex(re, im);
2481    } else {
2482        a = Float(a);
2483        if (a < 0) {
2484            return Complex(0, Float.sqrt(-a));
2485        } else {
2486            return Float.sqrt(a);
2487        }
2488    }
2489}
2490
2491function exp(a)
2492{
2493    return a.exp();
2494}
2495
2496function log(a)
2497{
2498    return a.log();
2499}
2500
2501function log2(a)
2502{
2503    return log(a) * Float.LOG2E;
2504}
2505
2506function log10(a)
2507{
2508    return log(a) * Float.LOG10E;
2509}
2510
2511function todb(a)
2512{
2513    return log10(a) * 10;
2514}
2515
2516function fromdb(a)
2517{
2518    return 10 ^ (a / 10);
2519}
2520
2521function sin(a)
2522{
2523    var t;
2524    if (a instanceof Complex || a instanceof Series) {
2525        t = exp(a * I);
2526        return (t - 1/t) / (2 * I);
2527    } else {
2528        return Float.sin(Float(a));
2529    }
2530}
2531
2532function cos(a)
2533{
2534    var t;
2535    if (a instanceof Complex || a instanceof Series) {
2536        t = exp(a * I);
2537        return (t + 1/t) / 2;
2538    } else {
2539        return Float.cos(Float(a));
2540    }
2541}
2542
2543function tan(a)
2544{
2545    if (a instanceof Complex || a instanceof Series) {
2546        return sin(a) / cos(a);
2547    } else {
2548        return Float.tan(Float(a));
2549    }
2550}
2551
2552function asin(a)
2553{
2554    return Float.asin(Float(a));
2555}
2556
2557function acos(a)
2558{
2559    return Float.acos(Float(a));
2560}
2561
2562function atan(a)
2563{
2564    return Float.atan(Float(a));
2565}
2566
2567function atan2(a, b)
2568{
2569    return Float.atan2(Float(a), Float(b));
2570}
2571
2572function sinc(a)
2573{
2574    if (a == 0) {
2575        return 1;
2576    } else {
2577        a *= Float.PI;
2578        return sin(a) / a;
2579    }
2580}
2581
2582function todeg(a)
2583{
2584    return a * 180 / Float.PI;
2585}
2586
2587function fromdeg(a)
2588{
2589    return a * Float.PI / 180;
2590}
2591
2592function sinh(a)
2593{
2594    var e = Float.exp(Float(a));
2595    return (e - 1/e) * 0.5;
2596}
2597
2598function cosh(a)
2599{
2600    var e = Float.exp(Float(a));
2601    return (e + 1/e) * 0.5;
2602}
2603
2604function tanh(a)
2605{
2606    var e = Float.exp(Float(a) * 2);
2607    return (e - 1) / (e + 1);
2608}
2609
2610function asinh(a)
2611{
2612    var x = Float(a);
2613    return log(sqrt(x * x + 1) + x);
2614}
2615
2616function acosh(a)
2617{
2618    var x = Float(a);
2619    return log(sqrt(x * x - 1) + x);
2620}
2621
2622function atanh(a)
2623{
2624    var x = Float(a);
2625    return 0.5 * log((1 + x) / (1 - x));
2626}
2627
2628var idn = Matrix.idn;
2629var diag = Matrix.diag;
2630var trans = Matrix.trans;
2631var trace = Matrix.trace;
2632var charpoly = Matrix.charpoly;
2633var eigenvals = Matrix.eigenvals;
2634var det = Matrix.det;
2635var rank = Matrix.rank;
2636var ker = Matrix.ker;
2637var cp = Matrix.cp;
2638var dp = Matrix.dp;
2639
2640var polroots = Polynomial.roots;
2641var bestappr = Float.bestappr;
2642