1 /*
  2     Copyright 2008-2023
  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";
 40 import Type from "../utils/type";
 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      * Initializes a vector as an array with the coefficients set to the given value resp. zero.
114      * @param {Number} n Length of the vector
115      * @param {Number} [init=0] Initial value for each coefficient
116      * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a
117      * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.
118      */
119     vector: function (n, init) {
120         var r, i;
121 
122         init = init || 0;
123         r = [];
124 
125         for (i = 0; i < n; i++) {
126             r[i] = init;
127         }
128 
129         return r;
130     },
131 
132     /**
133      * Initializes a matrix as an array of rows with the given value.
134      * @param {Number} n Number of rows
135      * @param {Number} [m=n] Number of columns
136      * @param {Number} [init=0] Initial value for each coefficient
137      * @returns {Array} A <tt>n</tt> times <tt>m</tt>-matrix represented by a
138      * two-dimensional array. The inner arrays hold the columns, the outer array holds the rows.
139      */
140     matrix: function (n, m, init) {
141         var r, i, j;
142 
143         init = init || 0;
144         m = m || n;
145         r = [];
146 
147         for (i = 0; i < n; i++) {
148             r[i] = [];
149 
150             for (j = 0; j < m; j++) {
151                 r[i][j] = init;
152             }
153         }
154 
155         return r;
156     },
157 
158     /**
159      * Generates an identity matrix. If n is a number and m is undefined or not a number, a square matrix is generated,
160      * if n and m are both numbers, an nxm matrix is generated.
161      * @param {Number} n Number of rows
162      * @param {Number} [m=n] Number of columns
163      * @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
164      * 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.
165      */
166     identity: function (n, m) {
167         var r, i;
168 
169         if (m === undef && typeof m !== "number") {
170             m = n;
171         }
172 
173         r = this.matrix(n, m);
174 
175         for (i = 0; i < Math.min(n, m); i++) {
176             r[i][i] = 1;
177         }
178 
179         return r;
180     },
181 
182     /**
183      * Generates a 4x4 matrix for 3D to 2D projections.
184      * @param {Number} l Left
185      * @param {Number} r Right
186      * @param {Number} t Top
187      * @param {Number} b Bottom
188      * @param {Number} n Near
189      * @param {Number} f Far
190      * @returns {Array} 4x4 Matrix
191      */
192     frustum: function (l, r, b, t, n, f) {
193         var ret = this.matrix(4, 4);
194 
195         ret[0][0] = (n * 2) / (r - l);
196         ret[0][1] = 0;
197         ret[0][2] = (r + l) / (r - l);
198         ret[0][3] = 0;
199 
200         ret[1][0] = 0;
201         ret[1][1] = (n * 2) / (t - b);
202         ret[1][2] = (t + b) / (t - b);
203         ret[1][3] = 0;
204 
205         ret[2][0] = 0;
206         ret[2][1] = 0;
207         ret[2][2] = -(f + n) / (f - n);
208         ret[2][3] = -(f * n * 2) / (f - n);
209 
210         ret[3][0] = 0;
211         ret[3][1] = 0;
212         ret[3][2] = -1;
213         ret[3][3] = 0;
214 
215         return ret;
216     },
217 
218     /**
219      * Generates a 4x4 matrix for 3D to 2D projections.
220      * @param {Number} fov Field of view in vertical direction, given in rad.
221      * @param {Number} ratio Aspect ratio of the projection plane.
222      * @param {Number} n Near
223      * @param {Number} f Far
224      * @returns {Array} 4x4 Projection Matrix
225      */
226     projection: function (fov, ratio, n, f) {
227         var t = n * Math.tan(fov / 2),
228             r = t * ratio;
229 
230         return this.frustum(-r, r, -t, t, n, f);
231     },
232 
233     /**
234      * 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
235      * function does not check if the dimensions match.
236      * @param {Array} mat Two dimensional array of numbers. The inner arrays describe the columns, the outer ones the matrix' rows.
237      * @param {Array} vec Array of numbers
238      * @returns {Array} Array of numbers containing the result
239      * @example
240      * var A = [[2, 1],
241      *          [1, 3]],
242      *     b = [4, 5],
243      *     c;
244      * c = JXG.Math.matVecMult(A, b)
245      * // c === [13, 19];
246      */
247     matVecMult: function (mat, vec) {
248         var i,
249             s,
250             k,
251             m = mat.length,
252             n = vec.length,
253             res = [];
254 
255         if (n === 3) {
256             for (i = 0; i < m; i++) {
257                 res[i] = mat[i][0] * vec[0] + mat[i][1] * vec[1] + mat[i][2] * vec[2];
258             }
259         } else {
260             for (i = 0; i < m; i++) {
261                 s = 0;
262                 for (k = 0; k < n; k++) {
263                     s += mat[i][k] * vec[k];
264                 }
265                 res[i] = s;
266             }
267         }
268         return res;
269     },
270 
271     /**
272      * Computes the product of the two matrices mat1*mat2.
273      * @param {Array} mat1 Two dimensional array of numbers
274      * @param {Array} mat2 Two dimensional array of numbers
275      * @returns {Array} Two dimensional Array of numbers containing result
276      */
277     matMatMult: function (mat1, mat2) {
278         var i,
279             j,
280             s,
281             k,
282             m = mat1.length,
283             n = m > 0 ? mat2[0].length : 0,
284             m2 = mat2.length,
285             res = this.matrix(m, n);
286 
287         for (i = 0; i < m; i++) {
288             for (j = 0; j < n; j++) {
289                 s = 0;
290                 for (k = 0; k < m2; k++) {
291                     s += mat1[i][k] * mat2[k][j];
292                 }
293                 res[i][j] = s;
294             }
295         }
296         return res;
297     },
298 
299     /**
300      * Transposes a matrix given as a two dimensional array.
301      * @param {Array} M The matrix to be transposed
302      * @returns {Array} The transpose of M
303      */
304     transpose: function (M) {
305         var MT, i, j, m, n;
306 
307         // number of rows of M
308         m = M.length;
309         // number of columns of M
310         n = M.length > 0 ? M[0].length : 0;
311         MT = this.matrix(n, m);
312 
313         for (i = 0; i < n; i++) {
314             for (j = 0; j < m; j++) {
315                 MT[i][j] = M[j][i];
316             }
317         }
318 
319         return MT;
320     },
321 
322     /**
323      * Compute the inverse of an nxn matrix with Gauss elimination.
324      * @param {Array} Ain
325      * @returns {Array} Inverse matrix of Ain
326      */
327     inverse: function (Ain) {
328         var i,
329             j,
330             k,
331             s,
332             ma,
333             r,
334             swp,
335             n = Ain.length,
336             A = [],
337             p = [],
338             hv = [];
339 
340         for (i = 0; i < n; i++) {
341             A[i] = [];
342             for (j = 0; j < n; j++) {
343                 A[i][j] = Ain[i][j];
344             }
345             p[i] = i;
346         }
347 
348         for (j = 0; j < n; j++) {
349             // pivot search:
350             ma = Math.abs(A[j][j]);
351             r = j;
352 
353             for (i = j + 1; i < n; i++) {
354                 if (Math.abs(A[i][j]) > ma) {
355                     ma = Math.abs(A[i][j]);
356                     r = i;
357                 }
358             }
359 
360             // Singular matrix
361             if (ma <= this.eps) {
362                 return [];
363             }
364 
365             // swap rows:
366             if (r > j) {
367                 for (k = 0; k < n; k++) {
368                     swp = A[j][k];
369                     A[j][k] = A[r][k];
370                     A[r][k] = swp;
371                 }
372 
373                 swp = p[j];
374                 p[j] = p[r];
375                 p[r] = swp;
376             }
377 
378             // transformation:
379             s = 1.0 / A[j][j];
380             for (i = 0; i < n; i++) {
381                 A[i][j] *= s;
382             }
383             A[j][j] = s;
384 
385             for (k = 0; k < n; k++) {
386                 if (k !== j) {
387                     for (i = 0; i < n; i++) {
388                         if (i !== j) {
389                             A[i][k] -= A[i][j] * A[j][k];
390                         }
391                     }
392                     A[j][k] = -s * A[j][k];
393                 }
394             }
395         }
396 
397         // swap columns:
398         for (i = 0; i < n; i++) {
399             for (k = 0; k < n; k++) {
400                 hv[p[k]] = A[i][k];
401             }
402             for (k = 0; k < n; k++) {
403                 A[i][k] = hv[k];
404             }
405         }
406 
407         return A;
408     },
409 
410     /**
411      * Inner product of two vectors a and b. n is the length of the vectors.
412      * @param {Array} a Vector
413      * @param {Array} b Vector
414      * @param {Number} [n] Length of the Vectors. If not given the length of the first vector is taken.
415      * @returns {Number} The inner product of a and b.
416      */
417     innerProduct: function (a, b, n) {
418         var i,
419             s = 0;
420 
421         if (n === undef || !Type.isNumber(n)) {
422             n = a.length;
423         }
424 
425         for (i = 0; i < n; i++) {
426             s += a[i] * b[i];
427         }
428 
429         return s;
430     },
431 
432     /**
433      * Calculates the cross product of two vectors both of length three.
434      * In case of homogeneous coordinates this is either
435      * <ul>
436      * <li>the intersection of two lines</li>
437      * <li>the line through two points</li>
438      * </ul>
439      * @param {Array} c1 Homogeneous coordinates of line or point 1
440      * @param {Array} c2 Homogeneous coordinates of line or point 2
441      * @returns {Array} vector of length 3: homogeneous coordinates of the resulting point / line.
442      */
443     crossProduct: function (c1, c2) {
444         return [
445             c1[1] * c2[2] - c1[2] * c2[1],
446             c1[2] * c2[0] - c1[0] * c2[2],
447             c1[0] * c2[1] - c1[1] * c2[0]
448         ];
449     },
450 
451     /**
452      * Euclidean norm of a vector.
453      *
454      * @param {Array} a Array containing a vector.
455      * @param {Number} n (Optional) length of the array.
456      * @returns {Number} Euclidean norm of the vector.
457      */
458     norm: function (a, n) {
459         var i,
460             sum = 0.0;
461 
462         if (n === undef || !Type.isNumber(n)) {
463             n = a.length;
464         }
465 
466         for (i = 0; i < n; i++) {
467             sum += a[i] * a[i];
468         }
469 
470         return Math.sqrt(sum);
471     },
472 
473     /**
474      * Compute a * x + y for a scalar a and vectors x and y.
475      *
476      * @param {Number} a
477      * @param {Array} x
478      * @param {Array} y
479      * @returns
480      */
481     axpy: function (a, x, y) {
482         var i,
483             le = x.length,
484             p = [];
485         for (i = 0; i < le; i++) {
486             p[i] = a * x[i] + y[i];
487         }
488         return p;
489     },
490 
491     /**
492      * Compute the factorial of a positive integer. If a non-integer value
493      * is given, the fraction will be ignored.
494      * @function
495      * @param {Number} n
496      * @returns {Number} n! = n*(n-1)*...*2*1
497      */
498     factorial: memoizer(function (n) {
499         if (n < 0) {
500             return NaN;
501         }
502 
503         n = Math.floor(n);
504 
505         if (n === 0 || n === 1) {
506             return 1;
507         }
508 
509         return n * this.factorial(n - 1);
510     }),
511 
512     /**
513      * Computes the binomial coefficient n over k.
514      * @function
515      * @param {Number} n Fraction will be ignored
516      * @param {Number} k Fraction will be ignored
517      * @returns {Number} The binomial coefficient n over k
518      */
519     binomial: memoizer(function (n, k) {
520         var b, i;
521 
522         if (k > n || k < 0) {
523             return NaN;
524         }
525 
526         k = Math.round(k);
527         n = Math.round(n);
528 
529         if (k === 0 || k === n) {
530             return 1;
531         }
532 
533         b = 1;
534 
535         for (i = 0; i < k; i++) {
536             b *= n - i;
537             b /= i + 1;
538         }
539 
540         return b;
541     }),
542 
543     /**
544      * Calculates the cosine hyperbolicus of x.
545      * @function
546      * @param {Number} x The number the cosine hyperbolicus will be calculated of.
547      * @returns {Number} Cosine hyperbolicus of the given value.
548      */
549     cosh:
550         Math.cosh ||
551         function (x) {
552             return (Math.exp(x) + Math.exp(-x)) * 0.5;
553         },
554 
555     /**
556      * Sine hyperbolicus of x.
557      * @function
558      * @param {Number} x The number the sine hyperbolicus will be calculated of.
559      * @returns {Number} Sine hyperbolicus of the given value.
560      */
561     sinh:
562         Math.sinh ||
563         function (x) {
564             return (Math.exp(x) - Math.exp(-x)) * 0.5;
565         },
566 
567     /**
568      * Hyperbolic arc-cosine of a number.
569      *
570      * @param {Number} x
571      * @returns {Number}
572      */
573     acosh:
574         Math.acosh ||
575         function (x) {
576             return Math.log(x + Math.sqrt(x * x - 1));
577         },
578 
579     /**
580      * Hyperbolic arcsine of a number
581      * @param {Number} x
582      * @returns {Number}
583      */
584     asinh:
585         Math.asinh ||
586         function (x) {
587             if (x === -Infinity) {
588                 return x;
589             }
590             return Math.log(x + Math.sqrt(x * x + 1));
591         },
592 
593     /**
594      * Computes the cotangent of x.
595      * @function
596      * @param {Number} x The number the cotangent will be calculated of.
597      * @returns {Number} Cotangent of the given value.
598      */
599     cot: function (x) {
600         return 1 / Math.tan(x);
601     },
602 
603     /**
604      * Computes the inverse cotangent of x.
605      * @param {Number} x The number the inverse cotangent will be calculated of.
606      * @returns {Number} Inverse cotangent of the given value.
607      */
608     acot: function (x) {
609         return (x >= 0 ? 0.5 : -0.5) * Math.PI - Math.atan(x);
610     },
611 
612     /**
613      * Compute n-th real root of a real number. n must be strictly positive integer.
614      * If n is odd, the real n-th root exists and is negative.
615      * For n even, for negative valuees of x NaN is returned
616      * @param  {Number} x radicand. Must be non-negative, if n even.
617      * @param  {Number} n index of the root. must be strictly positive integer.
618      * @returns {Number} returns real root or NaN
619      *
620      * @example
621      * nthroot(16, 4): 2
622      * nthroot(-27, 3): -3
623      * nthroot(-4, 2): NaN
624      */
625     nthroot: function (x, n) {
626         var inv = 1 / n;
627 
628         if (n <= 0 || Math.floor(n) !== n) {
629             return NaN;
630         }
631 
632         if (x === 0.0) {
633             return 0.0;
634         }
635 
636         if (x > 0) {
637             return Math.exp(inv * Math.log(x));
638         }
639 
640         // From here on, x is negative
641         if (n % 2 === 1) {
642             return -Math.exp(inv * Math.log(-x));
643         }
644 
645         // x negative, even root
646         return NaN;
647     },
648 
649     /**
650      * Computes cube root of real number
651      * Polyfill for Math.cbrt().
652      *
653      * @function
654      * @param  {Number} x Radicand
655      * @returns {Number} Cube root of x.
656      */
657     cbrt:
658         Math.cbrt ||
659         function (x) {
660             return this.nthroot(x, 3);
661         },
662 
663     /**
664      * Compute base to the power of exponent.
665      * @param {Number} base
666      * @param {Number} exponent
667      * @returns {Number} base to the power of exponent.
668      */
669     pow: function (base, exponent) {
670         if (base === 0) {
671             if (exponent === 0) {
672                 return 1;
673             }
674             return 0;
675         }
676 
677         // exponent is an integer
678         if (Math.floor(exponent) === exponent) {
679             return Math.pow(base, exponent);
680         }
681 
682         // exponent is not an integer
683         if (base > 0) {
684             return Math.exp(exponent * Math.log(base));
685         }
686 
687         return NaN;
688     },
689 
690     /**
691      * Compute base to the power of the rational exponent m / n.
692      * This function first reduces the fraction m/n and then computes
693      * JXG.Math.pow(base, m/n).
694      *
695      * This function is necessary to have the same results for e.g.
696      * (-8)^(1/3) = (-8)^(2/6) = -2
697      * @param {Number} base
698      * @param {Number} m numerator of exponent
699      * @param {Number} n denominator of exponent
700      * @returns {Number} base to the power of exponent.
701      */
702     ratpow: function (base, m, n) {
703         var g;
704         if (m === 0) {
705             return 1;
706         }
707         if (n === 0) {
708             return NaN;
709         }
710 
711         g = this.gcd(m, n);
712         return this.nthroot(this.pow(base, m / g), n / g);
713     },
714 
715     /**
716      * Logarithm to base 10.
717      * @param {Number} x
718      * @returns {Number} log10(x) Logarithm of x to base 10.
719      */
720     log10: function (x) {
721         return Math.log(x) / Math.log(10.0);
722     },
723 
724     /**
725      * Logarithm to base 2.
726      * @param {Number} x
727      * @returns {Number} log2(x) Logarithm of x to base 2.
728      */
729     log2: function (x) {
730         return Math.log(x) / Math.log(2.0);
731     },
732 
733     /**
734      * Logarithm to arbitrary base b. If b is not given, natural log is taken, i.e. b = e.
735      * @param {Number} x
736      * @param {Number} b base
737      * @returns {Number} log(x, b) Logarithm of x to base b, that is log(x)/log(b).
738      */
739     log: function (x, b) {
740         if (b !== undefined && Type.isNumber(b)) {
741             return Math.log(x) / Math.log(b);
742         }
743 
744         return Math.log(x);
745     },
746 
747     /**
748      * The sign() function returns the sign of a number, indicating whether the number is positive, negative or zero.
749      *
750      * @function
751      * @param  {Number} x A Number
752      * @returns {Number}  This function has 5 kinds of return values,
753      *    1, -1, 0, -0, NaN, which represent "positive number", "negative number", "positive zero", "negative zero"
754      *    and NaN respectively.
755      */
756     sign:
757         Math.sign ||
758         function (x) {
759             x = +x; // convert to a number
760             if (x === 0 || isNaN(x)) {
761                 return x;
762             }
763             return x > 0 ? 1 : -1;
764         },
765 
766     /**
767      * A square & multiply algorithm to compute base to the power of exponent.
768      * Implementated by Wolfgang Riedl.
769      *
770      * @param {Number} base
771      * @param {Number} exponent
772      * @returns {Number} Base to the power of exponent
773      */
774     squampow: function (base, exponent) {
775         var result;
776 
777         if (Math.floor(exponent) === exponent) {
778             // exponent is integer (could be zero)
779             result = 1;
780 
781             if (exponent < 0) {
782                 // invert: base
783                 base = 1.0 / base;
784                 exponent *= -1;
785             }
786 
787             while (exponent !== 0) {
788                 if (exponent & 1) {
789                     result *= base;
790                 }
791 
792                 exponent >>= 1;
793                 base *= base;
794             }
795             return result;
796         }
797 
798         return this.pow(base, exponent);
799     },
800 
801     /**
802      * Greatest common divisor (gcd) of two numbers.
803      * @see <a href="https://rosettacode.org/wiki/Greatest_common_divisor#JavaScript">rosettacode.org</a>
804      *
805      * @param  {Number} a First number
806      * @param  {Number} b Second number
807      * @returns {Number}   gcd(a, b) if a and b are numbers, NaN else.
808      */
809     gcd: function (a, b) {
810         var tmp,
811             endless = true;
812 
813         a = Math.abs(a);
814         b = Math.abs(b);
815 
816         if (!(Type.isNumber(a) && Type.isNumber(b))) {
817             return NaN;
818         }
819         if (b > a) {
820             tmp = a;
821             a = b;
822             b = tmp;
823         }
824 
825         while (endless) {
826             a %= b;
827             if (a === 0) {
828                 return b;
829             }
830             b %= a;
831             if (b === 0) {
832                 return a;
833             }
834         }
835     },
836 
837     /**
838      * Least common multiple (lcm) of two numbers.
839      *
840      * @param  {Number} a First number
841      * @param  {Number} b Second number
842      * @returns {Number}   lcm(a, b) if a and b are numbers, NaN else.
843      */
844     lcm: function (a, b) {
845         var ret;
846 
847         if (!(Type.isNumber(a) && Type.isNumber(b))) {
848             return NaN;
849         }
850 
851         ret = a * b;
852         if (ret !== 0) {
853             return ret / this.gcd(a, b);
854         }
855 
856         return 0;
857     },
858 
859     /**
860      *  Error function, see {@link https://en.wikipedia.org/wiki/Error_function}.
861      *
862      * @see JXG.Math.PropFunc.erf
863      * @param  {Number} x
864      * @returns {Number}
865      */
866     erf: function (x) {
867         return this.ProbFuncs.erf(x);
868     },
869 
870     /**
871      * Complementary error function, i.e. 1 - erf(x).
872      *
873      * @see JXG.Math.erf
874      * @see JXG.Math.PropFunc.erfc
875      * @param  {Number} x
876      * @returns {Number}
877      */
878     erfc: function (x) {
879         return this.ProbFuncs.erfc(x);
880     },
881 
882     /**
883      * Inverse of error function
884      *
885      * @see JXG.Math.erf
886      * @see JXG.Math.PropFunc.erfi
887      * @param  {Number} x
888      * @returns {Number}
889      */
890     erfi: function (x) {
891         return this.ProbFuncs.erfi(x);
892     },
893 
894     /**
895      * Normal distribution function
896      *
897      * @see JXG.Math.PropFunc.ndtr
898      * @param  {Number} x
899      * @returns {Number}
900      */
901     ndtr: function (x) {
902         return this.ProbFuncs.ndtr(x);
903     },
904 
905     /**
906      * Inverse of normal distribution function
907      *
908      * @see JXG.Math.ndtr
909      * @see JXG.Math.PropFunc.ndtri
910      * @param  {Number} x
911      * @returns {Number}
912      */
913     ndtri: function (x) {
914         return this.ProbFuncs.ndtri(x);
915     },
916 
917     /**
918      * Returns sqrt(a * a + b * b) for a variable number of arguments.
919      * This is a naive implementation which might be faster than Math.hypot.
920      * The latter is numerically more stable.
921      *
922      * @param {Number} a Variable number of arguments.
923      * @returns Number
924      */
925     hypot: function() {
926         var i, le, a, sum;
927 
928         le = arguments.length;
929         for (i = 0, sum = 0.0; i < le; i++) {
930             a = arguments[i];
931             sum += a * a;
932         }
933         return Math.sqrt(sum);
934     },
935 
936     /**
937      * Heaviside unit step function. Returns 0 for x <, 1 for x > 0, and 0.5 for x == 0.
938      *
939      * @param {Number} x
940      * @returns Number
941      */
942     hstep: function(x) {
943         return (x > 0.0) ? 1 :
944             ((x < 0.0) ? 0.0 : 0.5);
945     },
946 
947     /* ********************  Comparisons and logical operators ************** */
948 
949     /**
950      * Logical test: a < b?
951      *
952      * @param {Number} a
953      * @param {Number} b
954      * @returns {Boolean}
955      */
956     lt: function (a, b) {
957         return a < b;
958     },
959 
960     /**
961      * Logical test: a <= b?
962      *
963      * @param {Number} a
964      * @param {Number} b
965      * @returns {Boolean}
966      */
967     leq: function (a, b) {
968         return a <= b;
969     },
970 
971     /**
972      * Logical test: a > b?
973      *
974      * @param {Number} a
975      * @param {Number} b
976      * @returns {Boolean}
977      */
978     gt: function (a, b) {
979         return a > b;
980     },
981 
982     /**
983      * Logical test: a >= b?
984      *
985      * @param {Number} a
986      * @param {Number} b
987      * @returns {Boolean}
988      */
989     geq: function (a, b) {
990         return a >= b;
991     },
992 
993     /**
994      * Logical test: a === b?
995      *
996      * @param {Number} a
997      * @param {Number} b
998      * @returns {Boolean}
999      */
1000     eq: function (a, b) {
1001         return a === b;
1002     },
1003 
1004     /**
1005      * Logical test: a !== b?
1006      *
1007      * @param {Number} a
1008      * @param {Number} b
1009      * @returns {Boolean}
1010      */
1011     neq: function (a, b) {
1012         return a !== b;
1013     },
1014 
1015     /**
1016      * Logical operator: a && b?
1017      *
1018      * @param {Boolean} a
1019      * @param {Boolean} b
1020      * @returns {Boolean}
1021      */
1022     and: function (a, b) {
1023         return a && b;
1024     },
1025 
1026     /**
1027      * Logical operator: !a?
1028      *
1029      * @param {Boolean} a
1030      * @returns {Boolean}
1031      */
1032     not: function (a) {
1033         return !a;
1034     },
1035 
1036     /**
1037      * Logical operator: a || b?
1038      *
1039      * @param {Boolean} a
1040      * @param {Boolean} b
1041      * @returns {Boolean}
1042      */
1043     or: function (a, b) {
1044         return a || b;
1045     },
1046 
1047     /**
1048      * Logical operator: either a or b?
1049      *
1050      * @param {Boolean} a
1051      * @param {Boolean} b
1052      * @returns {Boolean}
1053      */
1054     xor: function (a, b) {
1055         return (a || b) && !(a && b);
1056     },
1057 
1058     /* *************************** Normalize *************************** */
1059 
1060     /**
1061      * Normalize the standard form [c, b0, b1, a, k, r, q0, q1].
1062      * @private
1063      * @param {Array} stdform The standard form to be normalized.
1064      * @returns {Array} The normalized standard form.
1065      */
1066     normalize: function (stdform) {
1067         var n,
1068             signr,
1069             a2 = 2 * stdform[3],
1070             r = stdform[4] / a2;
1071 
1072         stdform[5] = r;
1073         stdform[6] = -stdform[1] / a2;
1074         stdform[7] = -stdform[2] / a2;
1075 
1076         if (!isFinite(r)) {
1077             n = this.hypot(stdform[1], stdform[2]);
1078 
1079             stdform[0] /= n;
1080             stdform[1] /= n;
1081             stdform[2] /= n;
1082             stdform[3] = 0;
1083             stdform[4] = 1;
1084         } else if (Math.abs(r) >= 1) {
1085             stdform[0] = (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) / (2 * r);
1086             stdform[1] = -stdform[6] / r;
1087             stdform[2] = -stdform[7] / r;
1088             stdform[3] = 1 / (2 * r);
1089             stdform[4] = 1;
1090         } else {
1091             signr = r <= 0 ? -1 : 1;
1092             stdform[0] =
1093                 signr * (stdform[6] * stdform[6] + stdform[7] * stdform[7] - r * r) * 0.5;
1094             stdform[1] = -signr * stdform[6];
1095             stdform[2] = -signr * stdform[7];
1096             stdform[3] = signr / 2;
1097             stdform[4] = signr * r;
1098         }
1099 
1100         return stdform;
1101     },
1102 
1103     /**
1104      * Converts a two dimensional array to a one dimensional Float32Array that can be processed by WebGL.
1105      * @param {Array} m A matrix in a two dimensional array.
1106      * @returns {Float32Array} A one dimensional array containing the matrix in column wise notation. Provides a fall
1107      * back to the default JavaScript Array if Float32Array is not available.
1108      */
1109     toGL: function (m) {
1110         var v, i, j;
1111 
1112         if (typeof Float32Array === "function") {
1113             v = new Float32Array(16);
1114         } else {
1115             v = new Array(16);
1116         }
1117 
1118         if (m.length !== 4 && m[0].length !== 4) {
1119             return v;
1120         }
1121 
1122         for (i = 0; i < 4; i++) {
1123             for (j = 0; j < 4; j++) {
1124                 v[i + 4 * j] = m[i][j];
1125             }
1126         }
1127 
1128         return v;
1129     },
1130 
1131     /**
1132      * Theorem of Vieta: Given a set of simple zeroes x_0, ..., x_n
1133      * of a polynomial f, compute the coefficients s_k, (k=0,...,n-1)
1134      * of the polynomial of the form. See {@link https://de.wikipedia.org/wiki/Elementarsymmetrisches_Polynom}.
1135      * <p>
1136      *  f(x) = (x-x_0)*...*(x-x_n) =
1137      *  x^n + sum_{k=1}^{n} (-1)^(k) s_{k-1} x^(n-k)
1138      * </p>
1139      * @param {Array} x Simple zeroes of the polynomial.
1140      * @returns {Array} Coefficients of the polynomial.
1141      *
1142      */
1143     Vieta: function (x) {
1144         var n = x.length,
1145             s = [],
1146             m,
1147             k,
1148             y;
1149 
1150         s = x.slice();
1151         for (m = 1; m < n; ++m) {
1152             y = s[m];
1153             s[m] *= s[m - 1];
1154             for (k = m - 1; k >= 1; --k) {
1155                 s[k] += s[k - 1] * y;
1156             }
1157             s[0] += y;
1158         }
1159         return s;
1160     }
1161 };
1162 
1163 export default JXG.Math;
1164