      1 /*
      2     Copyright 2008-2024
      3         Matthias Ehmann,
      4         Michael Gerhaeuser,
      5         Carsten Miller,
      6         Bianca Valentin,
      7         Alfred Wassermann,
      8         Peter Wilfahrt
      9
     10     This file is part of JSXGraph.
     11
     12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
     13
     14     You can redistribute it and/or modify it under the terms of the
     15
     16       * GNU Lesser General Public License as published by
     17         the Free Software Foundation, either version 3 of the License, or
     18         (at your option) any later version
     19       OR
     20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
     21
     22     JSXGraph is distributed in the hope that it will be useful,
     23     but WITHOUT ANY WARRANTY; without even the implied warranty of
     24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     25     GNU Lesser General Public License for more details.
     26
     27     You should have received a copy of the GNU Lesser General Public License and
     28     the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
     29     and <https://opensource.org/licenses/MIT/>.
     30  */
     31
     32 /*global JXG: true, define: true, Float32Array: true */
     33 /*jslint nomen: true, plusplus: true, bitwise: true*/
     34
     35 /**
     36  * @fileoverview In this file the namespace JXG.Math is defined, which is the base namespace
     37  * for namespaces like JXG.Math.Numerics, JXG.Math.Plot, JXG.Math.Statistics, JXG.Math.Clip etc.
     38  */
     39 import JXG from "../jxg.js";
     40 import Type from "../utils/type.js";
     41
     42 var undef,
     43     /*
     44      * Dynamic programming approach for recursive functions.
     45      * From "Speed up your JavaScript, Part 3" by Nicholas C. Zakas.
     46      * @see JXG.Math.factorial
     47      * @see JXG.Math.binomial
     48      * http://blog.thejit.org/2008/09/05/memoization-in-javascript/
     49      *
     50      * This method is hidden, because it is only used in JXG.Math. If someone wants
     51      * to use it in JSXGraph outside of JXG.Math, it should be moved to jsxgraph.js
     52      */
     53     memoizer = function (f) {
     54         var cache, join;
     55
     56         if (f.memo) {
     57             return f.memo;
     58         }
     59
     60         cache = {};
     61         join = Array.prototype.join;
     62
     63         f.memo = function () {
     64             var key = join.call(arguments);
     65
     66             // Seems to be a bit faster than "if (a in b)"
     67             return cache[key] !== undef ? cache[key] : (cache[key] = f.apply(this, arguments));
     68         };
     69
     70         return f.memo;
     71     };
     72
     73 /**
     74  * Math namespace. Contains mathematics related methods which are
     75  * specific to JSXGraph or which extend the JavaScript Math class.
     76  * @namespace
     77  */
     78 JXG.Math = {
     79     /**
     80      * eps defines the closeness to zero. If the absolute value of a given number is smaller
     81      * than eps, it is considered to be equal to zero.
     82      * @type Number
     83      */
     84     eps: 0.000001,
     85
     86     /**
     87      * Determine the relative difference between two numbers.
     88      * @param  {Number} a First number
     89      * @param  {Number} b Second number
     90      * @returns {Number}  Relative difference between a and b: |a-b| / max(|a|, |b|)
     91      */
     92     relDif: function (a, b) {
     93         var c = Math.abs(a),
     94             d = Math.abs(b);
     95
     96         d = Math.max(c, d);
     97
     98         return d === 0.0 ? 0.0 : Math.abs(a - b) / d;
     99     },
    100
    101     /**
    102      * The JavaScript implementation of the % operator returns the symmetric modulo.
    103      * mod and "%" are both identical if a >= 0 and m >= 0 but the results differ if a or m < 0.
    104      * @param {Number} a
    105      * @param {Number} m
    106      * @returns {Number} Mathematical modulo <tt>a mod m</tt>
    107      */
    108     mod: function (a, m) {
    109         return a - Math.floor(a / m) * m;
    110     },
    111
    112     /**
    113      * Translate <code>x</code> into the interval <code>[a, b)</code> by adding
    114      * a multiple of <code>b - a</code>.
    115      * @param {Number} x
    116      * @param {Number} a
    117      * @param {Number} b
    118      */
    119     wrap: function (x, a, b) {
    120         return a + this.mod(x - a, b - a);
    121     },
    122
    123     /**
    124      * Clamp <code>x</code> within the interval <code>[a, b]</code>. If
    125      * <code>x</code> is below <code>a</code>, increase it to <code>a</code>. If
    126      * it's above <code>b</code>, decrease it to <code>b</code>.
    127      */
    128     clamp: function (x, a, b) {
    129         return Math.min(Math.max(x, a), b);
    130     },
    131
    132     /**
    133      * A way of clamping a periodic variable. If <code>x</code> is congruent mod
    134      * <code>period</code> to a point in <code>[a, b]</code>, return that point.
    135      * Otherwise, wrap it into <code>[mid - period/2, mid + period/2]</code>,
    136      * where <code>mid</code> is the mean of <code>a</code> and <code>b</code>,
    137      * and then clamp it to <code>[a, b]</code> from there.
    138      */
    139     wrapAndClamp: function (x, a, b, period) {
    140         var mid = 0.5 * (a + b),
    141             half_period = 0.5 * period;
    142
    143         return this.clamp(
    144             this.wrap(
    145                 x,
    146                 mid - half_period,
    147                 mid + half_period
    148             ),
    149             a,
    150             b
    151         );
    152     },
    153
    154     /**
    155      * Initializes a vector of size <tt>n</tt> wih coefficients set to the init value (default 0)
    156      * @param {Number} n Length of the vector
    157      * @param {Number} [init=0] Initial value for each coefficient
    158      * @returns {Array} An array of length <tt>n</tt>
    159      */
    160     vector: function (n, init) {
    161         var r, i;
    162
    163         init = init || 0;
    164         r = [];
    165
    166         for (i = 0; i < n; i++) {
    167             r[i] = init;
    168         }
    169
    170         return r;
    171     },
    172
    173     /**
    174      * Initializes a matrix as an array of rows with the given value.
    175      * @param {Number} n Number of rows
    176      * @param {Number} [m=n] Number of columns
    177      * @param {Number} [init=0] Initial value for each coefficient
    178      * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a
    179      * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.
    180      */
    181     matrix: function (n, m, init) {
    182         var r, i, j;
    183
    184         init = init || 0;
    185         m = m || n;
    186         r = [];
    187
    188         for (i = 0; i < n; i++) {
    189             r[i] = [];
    190
    191             for (j = 0; j < m; j++) {
    192                 r[i][j] = init;
    193             }
    194         }
    195
    196         return r;
    197     },
    198
    199     /**
    200      * Generates an identity matrix. If n is a number and m is undefined or not a number, a square matrix is generated,
    201      * if n and m are both numbers, an nxm matrix is generated.
    202      * @param {Number} n Number of rows
    203      * @param {Number} [m=n] Number of columns
    204      * @returns {Array} A square matrix of length <tt>n</tt> with all coefficients equal to 0 except a_(i,i), i out of (1, ..., n), if <tt>m</tt> is undefined or not a number
    205      * or a <tt>n</tt> times <tt>m</tt>-matrix with a_(i,j) = 0 and a_(i,i) = 1 if m is a number.
    206      */
    207     identity: function (n, m) {
    208         var r, i;
    209
    210         if (m === undef && typeof m !== "number") {
    211             m = n;
    212         }
    213
    214         r = this.matrix(n, m);
    215
    216         for (i = 0; i < Math.min(n, m); i++) {
    217             r[i][i] = 1;
    218         }
    219
    220         return r;
    221     },
    222
    223     /**
    224      * Generates a 4x4 matrix for 3D to 2D projections.
    225      * @param {Number} l Left
    226      * @param {Number} r Right
    227      * @param {Number} t Top
    228      * @param {Number} b Bottom
    229      * @param {Number} n Near
    230      * @param {Number} f Far
    231      * @returns {Array} 4x4 Matrix
    232      */
    233     frustum: function (l, r, b, t, n, f) {
    234         var ret = this.matrix(4, 4);
    235
    236         ret[0][0] = (n * 2) / (r - l);
    237         ret[0][1] = 0;
    238         ret[0][2] = (r + l) / (r - l);
    239         ret[0][3] = 0;
    240
    241         ret[1][0] = 0;
    242         ret[1][1] = (n * 2) / (t - b);
    243         ret[1][2] = (t + b) / (t - b);
    244         ret[1][3] = 0;
    245
    246         ret[2][0] = 0;
    247         ret[2][1] = 0;
    248         ret[2][2] = -(f + n) / (f - n);
    249         ret[2][3] = -(f * n * 2) / (f - n);
    250
    251         ret[3][0] = 0;
    252         ret[3][1] = 0;
    253         ret[3][2] = -1;
    254         ret[3][3] = 0;
    255
    256         return ret;
    257     },
    258
    259     /**
    260      * Generates a 4x4 matrix for 3D to 2D projections.
    261      * @param {Number} fov Field of view in vertical direction, given in rad.
    262      * @param {Number} ratio Aspect ratio of the projection plane.
    263      * @param {Number} n Near
    264      * @param {Number} f Far
    265      * @returns {Array} 4x4 Projection Matrix
    266      */
    267     projection: function (fov, ratio, n, f) {
    268         var t = n * Math.tan(fov / 2),
    269             r = t * ratio;
    270
    271         return this.frustum(-r, r, -t, t, n, f);
    272     },
    273
    274     /**
    275      * Multiplies a vector vec to a matrix mat: mat * vec. The matrix is interpreted by this function as an array of rows. Please note: This
    276      * function does not check if the dimensions match.
    277      * @param {Array} mat Two dimensional array of numbers. The inner arrays describe the columns, the outer ones the matrix' rows.
    278      * @param {Array} vec Array of numbers
    279      * @returns {Array} Array of numbers containing the result
    280      * @example
    281      * var A = [[2, 1],
    282      *          [1, 3]],
    283      *     b = [4, 5],
    284      *     c;
    285      * c = JXG.Math.matVecMult(A, b)
    286      * // c === [13, 19];
    287      */
    288     matVecMult: function (mat, vec) {
    289         var i,
    290             s,
    291             k,
    292             m = mat.length,
    293             n = vec.length,
    294             res = [];
    295
    296         if (n === 3) {
    297             for (i = 0; i < m; i++) {
    298                 res[i] = mat[i][0] * vec[0] + mat[i][1] * vec[1] + mat[i][2] * vec[2];
    299             }
    300         } else {
    301             for (i = 0; i < m; i++) {
    302                 s = 0;
    303                 for (k = 0; k < n; k++) {
    304                     s += mat[i][k] * vec[k];
    305                 }
    306                 res[i] = s;
    307             }
    308         }
    309         return res;
    310     },
    311
    312     /**
    313      * Computes the product of the two matrices mat1*mat2.
    314      * @param {Array} mat1 Two dimensional array of numbers
    315      * @param {Array} mat2 Two dimensional array of numbers
    316      * @returns {Array} Two dimensional Array of numbers containing result
    317      */
    318     matMatMult: function (mat1, mat2) {
    319         var i,
    320             j,
    321             s,
    322             k,
    323             m = mat1.length,
    324             n = m > 0 ? mat2[0].length : 0,
    325             m2 = mat2.length,
    326             res = this.matrix(m, n);
    327
    328         for (i = 0; i < m; i++) {
    329             for (j = 0; j < n; j++) {
    330                 s = 0;
    331                 for (k = 0; k < m2; k++) {
    332                     s += mat1[i][k] * mat2[k][j];
    333                 }
    334                 res[i][j] = s;
    335             }
    336         }
    337         return res;
    338     },
    339
    340     /**
    341      * Transposes a matrix given as a two dimensional array.
    342      * @param {Array} M The matrix to be transposed
    343      * @returns {Array} The transpose of M
    344      */
    345     transpose: function (M) {
    346         var MT, i, j, m, n;
    347
    348         // number of rows of M
    349         m = M.length;
    350         // number of columns of M
    351         n = M.length > 0 ? M[0].length : 0;
    352         MT = this.matrix(n, m);
    353
    354         for (i = 0; i < n; i++) {
    355             for (j = 0; j < m; j++) {
    356                 MT[i][j] = M[j][i];
    357             }
    358         }
    359
    360         return MT;
    361     },
    362
    363     /**
    364      * Compute the inverse of an nxn matrix with Gauss elimination.
    365      * @param {Array} Ain
    366      * @returns {Array} Inverse matrix of Ain
    367      */
    368     inverse: function (Ain) {
    369         var i,
    370             j,
    371             k,
    372             s,
    373             ma,
    374             r,
    375             swp,
    376             n = Ain.length,
    377             A = [],
    378             p = [],
    379             hv = [];
    380
    381         for (i = 0; i < n; i++) {
    382             A[i] = [];
    383             for (j = 0; j < n; j++) {
    384                 A[i][j] = Ain[i][j];
    385             }
    386             p[i] = i;
    387         }
    388
    389         for (j = 0; j < n; j++) {
    390             // pivot search:
    391             ma = Math.abs(A[j][j]);
    392             r = j;
    393
    394             for (i = j + 1; i < n; i++) {
    395                 if (Math.abs(A[i][j]) > ma) {
    396                     ma = Math.abs(A[i][j]);
    397                     r = i;
    398                 }
    399             }
    400
    401             // Singular matrix
    402             if (ma <= this.eps) {
    403                 return [];
    404             }
    405
    406             // swap rows:
    407             if (r > j) {
    408                 for (k = 0; k < n; k++) {
    409                     swp = A[j][k];
    410                     A[j][k] = A[r][k];
    411                     A[r][k] = swp;
    412                 }
    413
    414                 swp = p[j];
    415                 p[j] = p[r];
    416                 p[r] = swp;
    417             }
    418
    419             // transformation:
    420             s = 1.0 / A[j][j];
    421             for (i = 0; i < n; i++) {
    422                 A[i][j] *= s;
    423             }
    424             A[j][j] = s;
    425
    426             for (k = 0; k < n; k++) {
    427                 if (k !== j) {
    428                     for (i = 0; i < n; i++) {
    429                         if (i !== j) {
    430                             A[i][k] -= A[i][j] * A[j][k];
    431                         }
    432                     }
    433                     A[j][k] = -s * A[j][k];
    434                 }
    435             }
    436         }
    437
    438         // swap columns:
    439         for (i = 0; i < n; i++) {
    440             for (k = 0; k < n; k++) {
    441                 hv[p[k]] = A[i][k];
    442             }
    443             for (k = 0; k < n; k++) {
    444                 A[i][k] = hv[k];
    445             }
    446         }
    447
    448         return A;
    449     },
    450
    451     /**
    452      * Inner product of two vectors a and b. n is the length of the vectors.
    453      * @param {Array} a Vector
    454      * @param {Array} b Vector
    455      * @param {Number} [n] Length of the Vectors. If not given the length of the first vector is taken.
    456      * @returns {Number} The inner product of a and b.
    457      */
    458     innerProduct: function (a, b, n) {
    459         var i,
    460             s = 0;
    461
    462         if (n === undef || !Type.isNumber(n)) {
    463             n = a.length;
    464         }
    465
    466         for (i = 0; i < n; i++) {
    467             s += a[i] * b[i];
    468         }
    469
    470         return s;
    471     },
    472
    473     /**
    474      * Calculates the cross product of two vectors both of length three.
    475      * In case of homogeneous coordinates this is either
    476      * <ul>
    477      * <li>the intersection of two lines</li>
    478      * <li>the line through two points</li>
    479      * </ul>
    480      * @param {Array} c1 Homogeneous coordinates of line or point 1
    481      * @param {Array} c2 Homogeneous coordinates of line or point 2
    482      * @returns {Array} vector of length 3: homogeneous coordinates of the resulting point / line.
    483      */
    484     crossProduct: function (c1, c2) {
    485         return [
    486             c1[1] * c2[2] - c1[2] * c2[1],
    487             c1[2] * c2[0] - c1[0] * c2[2],
    488             c1[0] * c2[1] - c1[1] * c2[0]
    489         ];
    490     },
    491
    492     /**
    493      * Euclidean norm of a vector.
    494      *
    495      * @param {Array} a Array containing a vector.
    496      * @param {Number} n (Optional) length of the array.
    497      * @returns {Number} Euclidean norm of the vector.
    498      */
    499     norm: function (a, n) {
    500         var i,
    501             sum = 0.0;
    502
    503         if (n === undef || !Type.isNumber(n)) {
    504             n = a.length;
    505         }
    506
    507         for (i = 0; i < n; i++) {
    508             sum += a[i] * a[i];
    509         }
    510
    511         return Math.sqrt(sum);
    512     },
    513
    514     /**
    515      * Compute a * x + y for a scalar a and vectors x and y.
    516      *
    517      * @param {Number} a
    518      * @param {Array} x
    519      * @param {Array} y
    520      * @returns
    521      */
    522     axpy: function (a, x, y) {
    523         var i,
    524             le = x.length,
    525             p = [];
    526         for (i = 0; i < le; i++) {
    527             p[i] = a * x[i] + y[i];
    528         }
    529         return p;
    530     },
    531
    532     /**
    533      * Compute the factorial of a positive integer. If a non-integer value
    534      * is given, the fraction will be ignored.
    535      * @function
    536      * @param {Number} n
    537      * @returns {Number} n! = n*(n-1)*...*2*1
    538      */
    539     factorial: memoizer(function (n) {
    540         if (n < 0) {
    541             return NaN;
    542         }
    543
    544         n = Math.floor(n);
    545
    546         if (n === 0 || n === 1) {
    547             return 1;
    548         }
    549
    550         return n * this.factorial(n - 1);
    551     }),
    552
    553     /**
    554      * Computes the binomial coefficient n over k.
    555      * @function
    556      * @param {Number} n Fraction will be ignored
    557      * @param {Number} k Fraction will be ignored
    558      * @returns {Number} The binomial coefficient n over k
    559      */
    560     binomial: memoizer(function (n, k) {
    561         var b, i;
    562
    563         if (k > n || k < 0) {
    564             return NaN;
    565         }
    566
    567         k = Math.round(k);
    568         n = Math.round(n);
    569
    570         if (k === 0 || k === n) {
    571             return 1;
    572         }
    573
    574         b = 1;
    575
    576         for (i = 0; i < k; i++) {
    577             b *= n - i;
    578             b /= i + 1;
    579         }
    580
    581         return b;
    582     }),
    583
    584     /**
    585      * Calculates the cosine hyperbolicus of x.
    586      * @function
    587      * @param {Number} x The number the cosine hyperbolicus will be calculated of.
    588      * @returns {Number} Cosine hyperbolicus of the given value.
    589      */
    590     cosh:
    591         Math.cosh ||
    592         function (x) {
    593             return (Math.exp(x) + Math.exp(-x)) * 0.5;
    594         },
    595
    596     /**
    597      * Sine hyperbolicus of x.
    598      * @function
    599      * @param {Number} x The number the sine hyperbolicus will be calculated of.
    600      * @returns {Number} Sine hyperbolicus of the given value.
    601      */
    602     sinh:
    603         Math.sinh ||
    604         function (x) {
    605             return (Math.exp(x) - Math.exp(-x)) * 0.5;
    606         },
    607
    608     /**
    609      * Hyperbolic arc-cosine of a number.
    610      *
    611      * @param {Number} x
    612      * @returns {Number}
    613      */
    614     acosh:
    615         Math.acosh ||
    616         function (x) {
    617             return Math.log(x + Math.sqrt(x * x - 1));
    618         },
    619
    620     /**
    621      * Hyperbolic arcsine of a number
    622      * @param {Number} x
    623      * @returns {Number}
    624      */
    625     asinh:
    626         Math.asinh ||
    627         function (x) {
    628             if (x === -Infinity) {
    629                 return x;
    630             }
    631             return Math.log(x + Math.sqrt(x * x + 1));
    632         },
    633
    634     /**
    635      * Computes the cotangent of x.
    636      * @function
    637      * @param {Number} x The number the cotangent will be calculated of.
    638      * @returns {Number} Cotangent of the given value.
    639      */
    640     cot: function (x) {
    641         return 1 / Math.tan(x);
    642     },
    643
    644     /**
    645      * Computes the inverse cotangent of x.
    646      * @param {Number} x The number the inverse cotangent will be calculated of.
    647      * @returns {Number} Inverse cotangent of the given value.
    648      */
    649     acot: function (x) {
    650         return (x >= 0 ? 0.5 : -0.5) * Math.PI - Math.atan(x);
    651     },
    652
    653     /**
    654      * Compute n-th real root of a real number. n must be strictly positive integer.
    655      * If n is odd, the real n-th root exists and is negative.
    656      * For n even, for negative valuees of x NaN is returned
    657      * @param  {Number} x radicand. Must be non-negative, if n even.
    658      * @param  {Number} n index of the root. must be strictly positive integer.
    659      * @returns {Number} returns real root or NaN
    660      *
    661      * @example
    662      * nthroot(16, 4): 2
    663      * nthroot(-27, 3): -3
    664      * nthroot(-4, 2): NaN
    665      */
    666     nthroot: function (x, n) {
    667         var inv = 1 / n;
    668
    669         if (n <= 0 || Math.floor(n) !== n) {
    670             return NaN;
    671         }
    672
    673         if (x === 0.0) {
    674             return 0.0;
    675         }
    676
    677         if (x > 0) {
    678             return Math.exp(inv * Math.log(x));
    679         }
    680
    681         // From here on, x is negative
    682         if (n % 2 === 1) {
    683             return -Math.exp(inv * Math.log(-x));
    684         }
    685
    686         // x negative, even root
    687         return NaN;
    688     },
    689
    690     /**
    691      * Computes cube root of real number
    692      * Polyfill for Math.cbrt().
    693      *
    694      * @function
    695      * @param  {Number} x Radicand
    696      * @returns {Number} Cube root of x.
    697      */
    698     cbrt:
    699         Math.cbrt ||
    700         function (x) {
    701             return this.nthroot(x, 3);
    702         },
    703
    704     /**
    705      * Compute base to the power of exponent.
    706      * @param {Number} base
    707      * @param {Number} exponent
    708      * @returns {Number} base to the power of exponent.
    709      */
    710     pow: function (base, exponent) {
    711         if (base === 0) {
    712             if (exponent === 0) {
    713                 return 1;
    714             }
    715             return 0;
    716         }
    717
    718         // exponent is an integer
    719         if (Math.floor(exponent) === exponent) {
    720             return Math.pow(base, exponent);
    721         }
    722
    723         // exponent is not an integer
    724         if (base > 0) {
    725             return Math.exp(exponent * Math.log(base));
    726         }
    727
    728         return NaN;
    729     },
    730
    731     /**
    732      * Compute base to the power of the rational exponent m / n.
    733      * This function first reduces the fraction m/n and then computes
    734      * JXG.Math.pow(base, m/n).
    735      *
    736      * This function is necessary to have the same results for e.g.
    737      * (-8)^(1/3) = (-8)^(2/6) = -2
    738      * @param {Number} base
    739      * @param {Number} m numerator of exponent
    740      * @param {Number} n denominator of exponent
    741      * @returns {Number} base to the power of exponent.
    742      */
    743     ratpow: function (base, m, n) {
    744         var g;
    745         if (m === 0) {
    746             return 1;
    747         }
    748         if (n === 0) {
    749             return NaN;
    750         }
    751
    752         g = this.gcd(m, n);
    753         return this.nthroot(this.pow(base, m / g), n / g);
    754     },
    755
    756     /**
    757      * Logarithm to base 10.
    758      * @param {Number} x
    759      * @returns {Number} log10(x) Logarithm of x to base 10.
    760      */
    761     log10: function (x) {
    762         return Math.log(x) / Math.log(10.0);
    763     },
    764
    765     /**
    766      * Logarithm to base 2.
    767      * @param {Number} x
    768      * @returns {Number} log2(x) Logarithm of x to base 2.
    769      */
    770     log2: function (x) {
    771         return Math.log(x) / Math.log(2.0);
    772     },
    773
    774     /**
    775      * Logarithm to arbitrary base b. If b is not given, natural log is taken, i.e. b = e.
    776      * @param {Number} x
    777      * @param {Number} b base
    778      * @returns {Number} log(x, b) Logarithm of x to base b, that is log(x)/log(b).
    779      */
    780     log: function (x, b) {
    781         if (b !== undefined && Type.isNumber(b)) {
    782             return Math.log(x) / Math.log(b);
    783         }
    784
    785         return Math.log(x);
    786     },
    787
    788     /**
    789      * The sign() function returns the sign of a number, indicating whether the number is positive, negative or zero.
    790      *
    791      * @function
    792      * @param  {Number} x A Number
    793      * @returns {Number}  This function has 5 kinds of return values,
    794      *    1, -1, 0, -0, NaN, which represent "positive number", "negative number", "positive zero", "negative zero"
    795      *    and NaN respectively.
    796      */
    797     sign:
    798         Math.sign ||
    799         function (x) {
    800             x = +x; // convert to a number
    801             if (x === 0 || isNaN(x)) {
    802                 return x;
    803             }
    804             return x > 0 ? 1 : -1;
    805         },
    806
    807     /**
    808      * A square & multiply algorithm to compute base to the power of exponent.
    809      * Implementated by Wolfgang Riedl.
    810      *
    811      * @param {Number} base
    812      * @param {Number} exponent
    813      * @returns {Number} Base to the power of exponent
    814      */
    815     squampow: function (base, exponent) {
    816         var result;
    817
    818         if (Math.floor(exponent) === exponent) {
    819             // exponent is integer (could be zero)
    820             result = 1;
    821
    822             if (exponent < 0) {
    823                 // invert: base
    824                 base = 1.0 / base;
    825                 exponent *= -1;
    826             }
    827
    828             while (exponent !== 0) {
    829                 if (exponent & 1) {
    830                     result *= base;
    831                 }
    832
    833                 exponent >>= 1;
    834                 base *= base;
    835             }
    836             return result;
    837         }
    838
    839         return this.pow(base, exponent);
    840     },
    841
    842     /**
    843      * Greatest common divisor (gcd) of two numbers.
    844      * @see <a href="https://rosettacode.org/wiki/Greatest_common_divisor#JavaScript">rosettacode.org</a>
    845      *
    846      * @param  {Number} a First number
    847      * @param  {Number} b Second number
    848      * @returns {Number}   gcd(a, b) if a and b are numbers, NaN else.
    849      */
    850     gcd: function (a, b) {
    851         var tmp,
    852             endless = true;
    853
    854         a = Math.abs(a);
    855         b = Math.abs(b);
    856
    857         if (!(Type.isNumber(a) && Type.isNumber(b))) {
    858             return NaN;
    859         }
    860         if (b > a) {
    861             tmp = a;
    862             a = b;
    863             b = tmp;
    864         }
    865
    866         while (endless) {
    867             a %= b;
    868             if (a === 0) {
    869                 return b;
    870             }
    871             b %= a;
    872             if (b === 0) {
    873                 return a;
    874             }
    875         }
    876     },
    877
    878     /**
    879      * Least common multiple (lcm) of two numbers.
    880      *
    881      * @param  {Number} a First number
    882      * @param  {Number} b Second number
    883      * @returns {Number}   lcm(a, b) if a and b are numbers, NaN else.
    884      */
    885     lcm: function (a, b) {
    886         var ret;
    887
    888         if (!(Type.isNumber(a) && Type.isNumber(b))) {
    889             return NaN;
    890         }
    891
    892         ret = a * b;
    893         if (ret !== 0) {
    894             return ret / this.gcd(a, b);
    895         }
    896
    897         return 0;
    898     },
    899
    900     /**
    901      * Special use of Math.round function to round not only to integers but also to chosen decimal values.
    902      *
    903      * @param {Number} value Value to be rounded.
    904      * @param {Number} step Distance between the values to be rounded to. (default: 1.0)
    905      * @param {Number} [min] If set, it will be returned the maximum of value and min.
    906      * @param {Number} [max] If set, it will be returned the minimum of value and max.
    907      * @returns {Number} Fitted value.
    908      */
    909     roundToStep: function (value, step, min, max) {
    910         var n = value,
    911             tmp, minOr0;
    912
    913         // for performance
    914         if (!Type.exists(step) && !Type.exists(min) && !Type.exists(max)) {
    915             return n;
    916         }
    917
    918         if (JXG.exists(max)) {
    919             n = Math.min(n, max);
    920         }
    921         if (JXG.exists(min)) {
    922             n = Math.max(n, min);
    923         }
    924
    925         minOr0 = min || 0;
    926
    927         if (JXG.exists(step)) {
    928             tmp = (n - minOr0) / step;
    929             if (Number.isInteger(tmp)) {
    930                 return n;
    931             }
    932
    933             tmp = Math.round(tmp);
    934             n = minOr0 + tmp * step;
    935         }
    936
    937         if (JXG.exists(max)) {
    938             n = Math.min(n, max);
    939         }
    940         if (JXG.exists(min)) {
    941             n = Math.max(n, min);
    942         }
    943
    944         return n;
    945     },
    946
    947     /**
    948      *  Error function, see {@link https://en.wikipedia.org/wiki/Error_function}.
    949      *
    950      * @see JXG.Math.PropFunc.erf
    951      * @param  {Number} x
    952      * @returns {Number}
    953      */
    954     erf: function (x) {
    955         return this.ProbFuncs.erf(x);
    956     },
    957
    958     /**
    959      * Complementary error function, i.e. 1 - erf(x).
    960      *
    961      * @see JXG.Math.erf
    962      * @see JXG.Math.PropFunc.erfc
    963      * @param  {Number} x
    964      * @returns {Number}
    965      */
    966     erfc: function (x) {
    967         return this.ProbFuncs.erfc(x);
    968     },
    969
    970     /**
    971      * Inverse of error function
    972      *
    973      * @see JXG.Math.erf
    974      * @see JXG.Math.PropFunc.erfi
    975      * @param  {Number} x
    976      * @returns {Number}
    977      */
    978     erfi: function (x) {
    979         return this.ProbFuncs.erfi(x);
    980     },
    981
    982     /**
    983      * Normal distribution function
    984      *
    985      * @see JXG.Math.PropFunc.ndtr
    986      * @param  {Number} x
    987      * @returns {Number}
    988      */
    989     ndtr: function (x) {
    990         return this.ProbFuncs.ndtr(x);
    991     },
    992
    993     /**
    994      * Inverse of normal distribution function
    995      *
    996      * @see JXG.Math.ndtr
    997      * @see JXG.Math.PropFunc.ndtri
    998      * @param  {Number} x
    999      * @returns {Number}
    1000      */
    1001     ndtri: function (x) {
    1002         return this.ProbFuncs.ndtri(x);
    1003     },
    1004
    1005     /**
    1006      * Returns sqrt(a * a + b * b) for a variable number of arguments.
    1007      * This is a naive implementation which might be faster than Math.hypot.
    1008      * The latter is numerically more stable.
    1009      *
    1010      * @param {Number} a Variable number of arguments.
    1011      * @returns Number
    1012      */
    1013     hypot: function () {
    1014         var i, le, a, sum;
    1015
    1016         le = arguments.length;
    1017         for (i = 0, sum = 0.0; i < le; i++) {
    1018             a = arguments[i];
    1019             sum += a * a;
    1020         }
    1021         return Math.sqrt(sum);
    1022     },
    1023
    1024     /**
    1025      * Heaviside unit step function. Returns 0 for x <, 1 for x > 0, and 0.5 for x == 0.
    1026      *
    1027      * @param {Number} x
    1028      * @returns Number
    1029      */
    1030     hstep: function (x) {
    1031         return (x > 0.0) ? 1 :
    1032             ((x < 0.0) ? 0.0 : 0.5);
    1033     },
    1034
    1035     /**
    1036      * Gamma function for real parameters by Lanczos approximation.
    1037      * Implementation straight from {@link https://en.wikipedia.org/wiki/Lanczos_approximation}.
    1038      *
    1039      * @param {Number} z
    1040      * @returns Number
    1041      */
    1042     gamma: function (z) {
    1043         var x, y, t, i, le,
    1044             g = 7,
    1045             // n = 9,
    1046             p = [
    1047                 1.0,
    1048                 676.5203681218851,
    1049                 -1259.1392167224028,
    1050                 771.32342877765313,
    1051                 -176.61502916214059,
    1052                 12.507343278686905,
    1053                 -0.13857109526572012,
    1054                 9.9843695780195716e-6,
    1055                 1.5056327351493116e-7
    1056             ];
    1057
    1058         if (z < 0.5) {
    1059             y = Math.PI / (Math.sin(Math.PI * z) * this.gamma(1 - z));  // Reflection formula
    1060         } else {
    1061             z -= 1;
    1062             x = p[0];
    1063             le = p.length;
    1064             for (i = 1; i < le; i++) {
    1065                 x += p[i] / (z + i);
    1066             }
    1067             t = z + g + 0.5;
    1068             y = Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
    1069         }
    1070         return y;
    1071     },
    1072
    1073     /* ********************  Comparisons and logical operators ************** */
    1074
    1075     /**
    1076      * Logical test: a < b?
    1077      *
    1078      * @param {Number} a
    1079      * @param {Number} b
    1080      * @returns {Boolean}
    1081      */
    1082     lt: function (a, b) {
    1083         return a < b;
    1084     },
    1085
    1086     /**
    1087      * Logical test: a <= b?
    1088      *
    1089      * @param {Number} a
    1090      * @param {Number} b
    1091      * @returns {Boolean}
    1092      */
    1093     leq: function (a, b) {
    1094         return a <= b;
    1095     },
    1096
    1097     /**
    1098      * Logical test: a > b?
    1099      *
    1100      * @param {Number} a
    1101      * @param {Number} b
    1102      * @returns {Boolean}
    1103      */
    1104     gt: function (a, b) {
    1105         return a > b;
    1106     },
    1107
    1108     /**
    1109      * Logical test: a >= b?
    1110      *
    1111      * @param {Number} a
    1112      * @param {Number} b
    1113      * @returns {Boolean}
    1114      */
    1115     geq: function (a, b) {
    1116         return a >= b;
    1117     },
    1118
    1119     /**
    1120      * Logical test: a === b?
    1121      *
    1122      * @param {Number} a
    1123      * @param {Number} b
    1124      * @returns {Boolean}
    1125      */
    1126     eq: function (a, b) {
    1127         return a === b;
    1128     },
    1129
    1130     /**
    1131      * Logical test: a !== b?
    1132      *
    1133      * @param {Number} a
    1134      * @param {Number} b
    1135      * @returns {Boolean}
    1136      */
    1137     neq: function (a, b) {
    1138         return a !== b;
    1139     },
    1140
    1141     /**
    1142      * Logical operator: a && b?
    1143      *
    1144      * @param {Boolean} a
    1145      * @param {Boolean} b
    1146      * @returns {Boolean}
    1147      */
    1148     and: function (a, b) {
    1149         return a && b;
    1150     },
    1151
    1152     /**
    1153      * Logical operator: !a?
    1154      *
    1155      * @param {Boolean} a
    1156      * @returns {Boolean}
    1157      */
    1158     not: function (a) {
    1159         return !a;
    1160     },
    1161
    1162     /**
    1163      * Logical operator: a || b?
    1164      *
    1165      * @param {Boolean} a
    1166      * @param {Boolean} b
    1167      * @returns {Boolean}
    1168      */
    1169     or: function (a, b) {
    1170         return a || b;
    1171     },
    1172
    1173     /**
    1174      * Logical operator: either a or b?
    1175      *
    1176      * @param {Boolean} a
    1177      * @param {Boolean} b
    1178      * @returns {Boolean}
    1179      */
    1180     xor: function (a, b) {
    1181         return (a || b) && !(a && b);
    1182     },
    1183
    1184     /**
    1185      *
    1186      * Convert a floating point number to sign + integer + fraction.
    1187      * fraction is given as nominator and denominator.
    1188      * <p>
    1189      * Algorithm: approximate the floating point number
    1190      * by a continued fraction and simultaneously keep track
    1191      * of its convergents.
    1192      * Inspired by {@link https://kevinboone.me/rationalize.html}.
    1193      *
    1194      * @param {Number} x Number which is to be converted
    1195      * @param {Number} [order=0.001] Small number determining the approximation precision.
    1196      * @returns {Array} [sign, leading, nominator, denominator] where sign is 1 or -1.
    1197      * @see JXG#toFraction
    1198      *
    1199      * @example
    1200      * JXG.Math.decToFraction(0.33333333);
    1201      * // Result: [ 1, 0, 1, 3 ]
    1202      *
    1203      * JXG.Math.decToFraction(0);
    1204      * // Result: [ 1, 0, 0, 1 ]
    1205      *
    1206      * JXG.Math.decToFraction(-10.66666666666667);
    1207      * // Result: [-1, 10, 2, 3 ]
    1208     */
    1209     decToFraction: function (x, order) {
    1210         var lead, sign, a,
    1211             n, n1, n2,
    1212             d, d1, d2,
    1213             it = 0,
    1214             maxit = 20;
    1215
    1216         order = Type.def(order, 0.001);
    1217
    1218         // Round the number.
    1219         // Otherwise, 0.999999999 would result in [0, 1, 1].
    1220         x = Math.round(x * 1.e12) * 1.e-12;
    1221
    1222         // Negative numbers:
    1223         // The minus sign is handled in sign.
    1224         sign = (x < 0) ? -1 : 1;
    1225         x = Math.abs(x);
    1226
    1227         // From now on we consider x to be nonnegative.
    1228         lead = Math.floor(x);
    1229         x -= Math.floor(x);
    1230         a = 0.0;
    1231         n2 = 1.0;
    1232         n = n1 = a;
    1233         d2 = 0.0;
    1234         d = d1 = 1.0;
    1235
    1236         while (x - Math.floor(x) > order && it < maxit) {
    1237             x = 1 / (x - a);
    1238             a = Math.floor(x);
    1239             n = n2 + a * n1;
    1240             d = d2 + a * d1;
    1241             n2 = n1;
    1242             d2 = d1;
    1243             n1 = n;
    1244             d1 = d;
    1245             it++;
    1246         }
    1247         return [sign, lead, n, d];
    1248     },
    1249
    1250     /* *************************** Normalize *************************** */
    1251
    1252     /**
    1253      * Normalize the standard form [c, b0, b1, a, k, r, q0, q1].
    1254      * @private
    1255      * @param {Array} stdform The standard form to be normalized.
    1256      * @returns {Array} The normalized standard form.
    1257      */
    1258     normalize: function (stdform) {
    1259         var n,
    1260             signr,
    1261             a2 = 2 * stdform[3],
    1262             r = stdform[4] / a2;
    1263
    1264         stdform[5] = r;
    1265         stdform[6] = -stdform[1] / a2;
    1266         stdform[7] = -stdform[2] / a2;
    1267
    1268         if (!isFinite(r)) {
    1269             n = this.hypot(stdform[1], stdform[2]);
    1270
    1271             stdform[0] /= n;
    1272             stdform[1] /= n;
    1273             stdform[2] /= n;
    1274             stdform[3] = 0;
    1275             stdform[4] = 1;
    1276         } else if (Math.abs(r) >= 1) {
    1277             stdform[0] = (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) / (2 * r);
    1278             stdform[1] = -stdform[6] / r;
    1279             stdform[2] = -stdform[7] / r;
    1280             stdform[3] = 1 / (2 * r);
    1281             stdform[4] = 1;
    1282         } else {
    1283             signr = r <= 0 ? -1 : 1;
    1284             stdform[0] =
    1285                 signr * (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) * 0.5;
    1286             stdform[1] = -signr * stdform[6];
    1287             stdform[2] = -signr * stdform[7];
    1288             stdform[3] = signr / 2;
    1289             stdform[4] = signr * r;
    1290         }
    1291
    1292         return stdform;
    1293     },
    1294
    1295     /**
    1296      * Converts a two dimensional array to a one dimensional Float32Array that can be processed by WebGL.
    1297      * @param {Array} m A matrix in a two dimensional array.
    1298      * @returns {Float32Array} A one dimensional array containing the matrix in column wise notation. Provides a fall
    1299      * back to the default JavaScript Array if Float32Array is not available.
    1300      */
    1301     toGL: function (m) {
    1302         var v, i, j;
    1303
    1304         if (typeof Float32Array === "function") {
    1305             v = new Float32Array(16);
    1306         } else {
    1307             v = new Array(16);
    1308         }
    1309
    1310         if (m.length !== 4 && m[0].length !== 4) {
    1311             return v;
    1312         }
    1313
    1314         for (i = 0; i < 4; i++) {
    1315             for (j = 0; j < 4; j++) {
    1316                 v[i + 4 * j] = m[i][j];
    1317             }
    1318         }
    1319
    1320         return v;
    1321     },
    1322
    1323     /**
    1324      * Theorem of Vieta: Given a set of simple zeroes x_0, ..., x_n
    1325      * of a polynomial f, compute the coefficients s_k, (k=0,...,n-1)
    1326      * of the polynomial of the form. See {@link https://de.wikipedia.org/wiki/Elementarsymmetrisches_Polynom}.
    1327      * <p>
    1328      *  f(x) = (x-x_0)*...*(x-x_n) =
    1329      *  x^n + sum_{k=1}^{n} (-1)^(k) s_{k-1} x^(n-k)
    1330      * </p>
    1331      * @param {Array} x Simple zeroes of the polynomial.
    1332      * @returns {Array} Coefficients of the polynomial.
    1333      *
    1334      */
    1335     Vieta: function (x) {
    1336         var n = x.length,
    1337             s = [],
    1338             m,
    1339             k,
    1340             y;
    1341
    1342         s = x.slice();
    1343         for (m = 1; m < n; ++m) {
    1344             y = s[m];
    1345             s[m] *= s[m - 1];
    1346             for (k = m - 1; k >= 1; --k) {
    1347                 s[k] += s[k - 1] * y;
    1348             }
    1349             s[0] += y;
    1350         }
    1351         return s;
    1352     }
    1353 };
    1354
    1355 export default JXG.Math;
    1356