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