1 /* 2 Copyright 2008-2023 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Alfred Wassermann 7 8 This file is part of JSXGraph. 9 10 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 11 12 You can redistribute it and/or modify it under the terms of the 13 14 * GNU Lesser General Public License as published by 15 the Free Software Foundation, either version 3 of the License, or 16 (at your option) any later version 17 OR 18 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 19 20 JSXGraph is distributed in the hope that it will be useful, 21 but WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 GNU Lesser General Public License for more details. 24 25 You should have received a copy of the GNU Lesser General Public License and 26 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 27 and <https://opensource.org/licenses/MIT/>. 28 */ 29 30 /*global JXG: true, define: true*/ 31 /*jslint nomen: true, plusplus: true*/ 32 33 import JXG from "../jxg"; 34 import Mat from "./math"; 35 import Type from "../utils/type"; 36 37 JXG.Math.DoubleBits = function () { 38 var hasTypedArrays = false, 39 DOUBLE_VIEW = new Float64Array(1), 40 UINT_VIEW = new Uint32Array(DOUBLE_VIEW.buffer), 41 doubleBitsLE, 42 toDoubleLE, 43 lowUintLE, 44 highUintLE, 45 doubleBitsBE, 46 toDoubleBE, 47 lowUintBE, 48 highUintBE, 49 doubleBits, 50 toDouble, 51 lowUint, 52 highUint; 53 54 if (Float64Array !== undefined) { 55 DOUBLE_VIEW[0] = 1.0; 56 hasTypedArrays = true; 57 if (UINT_VIEW[1] === 0x3ff00000) { 58 // Use little endian 59 doubleBitsLE = function (n) { 60 DOUBLE_VIEW[0] = n; 61 return [UINT_VIEW[0], UINT_VIEW[1]]; 62 }; 63 toDoubleLE = function (lo, hi) { 64 UINT_VIEW[0] = lo; 65 UINT_VIEW[1] = hi; 66 return DOUBLE_VIEW[0]; 67 }; 68 69 lowUintLE = function (n) { 70 DOUBLE_VIEW[0] = n; 71 return UINT_VIEW[0]; 72 }; 73 74 highUintLE = function (n) { 75 DOUBLE_VIEW[0] = n; 76 return UINT_VIEW[1]; 77 }; 78 79 this.doubleBits = doubleBitsLE; 80 this.pack = toDoubleLE; 81 this.lo = lowUintLE; 82 this.hi = highUintLE; 83 } else if (UINT_VIEW[0] === 0x3ff00000) { 84 //Use big endian 85 doubleBitsBE = function (n) { 86 DOUBLE_VIEW[0] = n; 87 return [UINT_VIEW[1], UINT_VIEW[0]]; 88 }; 89 90 toDoubleBE = function (lo, hi) { 91 UINT_VIEW[1] = lo; 92 UINT_VIEW[0] = hi; 93 return DOUBLE_VIEW[0]; 94 }; 95 96 lowUintBE = function (n) { 97 DOUBLE_VIEW[0] = n; 98 return UINT_VIEW[1]; 99 }; 100 101 highUintBE = function (n) { 102 DOUBLE_VIEW[0] = n; 103 return UINT_VIEW[0]; 104 }; 105 106 this.doubleBits = doubleBitsBE; 107 this.pack = toDoubleBE; 108 this.lo = lowUintBE; 109 this.hi = highUintBE; 110 } else { 111 hasTypedArrays = false; 112 } 113 } 114 115 // if (!hasTypedArrays) { 116 // var buffer = new Buffer(8) 117 // doubleBits = function(n) { 118 // buffer.writeDoubleLE(n, 0, true); 119 // return [buffer.readUInt32LE(0, true), buffer.readUInt32LE(4, true)]; 120 // }; 121 122 // toDouble = function(lo, hi) { 123 // buffer.writeUInt32LE(lo, 0, true); 124 // buffer.writeUInt32LE(hi, 4, true); 125 // return buffer.readDoubleLE(0, true); 126 // }; 127 // lowUint = function(n) { 128 // buffer.writeDoubleLE(n, 0, true); 129 // return buffer.readUInt32LE(0, true); 130 // }; 131 132 // highUint = function(n) { 133 // buffer.writeDoubleLE(n, 0, true); 134 // return buffer.readUInt32LE(4, true); 135 // }; 136 137 // this.doubleBits = doubleBits; 138 // this.pack = toDouble; 139 // this.lo = lowUint; 140 // this.hi = highUint; 141 // } 142 }; 143 144 JXG.extend( 145 JXG.Math.DoubleBits.prototype, 146 /** @lends JXG.Math.DoubleBits.prototype */ { 147 sign: function (n) { 148 return this.hi(n) >>> 31; 149 }, 150 151 exponent: function (n) { 152 var b = this.hi(n); 153 return ((b << 1) >>> 21) - 1023; 154 }, 155 156 fraction: function (n) { 157 var lo = this.lo(n), 158 hi = this.hi(n), 159 b = hi & ((1 << 20) - 1); 160 161 if (hi & 0x7ff00000) { 162 b += 1 << 20; 163 } 164 return [lo, b]; 165 }, 166 167 denormalized: function (n) { 168 var hi = this.hi(n); 169 return !(hi & 0x7ff00000); 170 } 171 } 172 ); 173 174 var doubleBits = new JXG.Math.DoubleBits(), 175 /** 176 * Interval for interval arithmetics. Consists of the properties 177 * <ul> 178 * <li>lo 179 * <li>hi 180 * </ul> 181 * @name JXG.Math.Interval 182 * @type Object 183 */ 184 MatInterval = function (lo, hi) { 185 if (lo !== undefined && hi !== undefined) { 186 // possible cases: 187 // - Interval(1, 2) 188 // - Interval(Interval(1, 1), Interval(2, 2)) // singletons are required 189 if (Mat.IntervalArithmetic.isInterval(lo)) { 190 if (!Mat.IntervalArithmetic.isSingleton(lo)) { 191 throw new TypeError( 192 "JXG.Math.IntervalArithmetic: interval `lo` must be a singleton" 193 ); 194 } 195 this.lo = lo.lo; 196 } else { 197 this.lo = lo; 198 } 199 if (Mat.IntervalArithmetic.isInterval(hi)) { 200 if (!Mat.IntervalArithmetic.isSingleton(hi)) { 201 throw new TypeError( 202 "JXG.Math.IntervalArithmetic: interval `hi` must be a singleton" 203 ); 204 } 205 this.hi = hi.hi; 206 } else { 207 this.hi = hi; 208 } 209 } else if (lo !== undefined) { 210 // possible cases: 211 // - Interval([1, 2]) 212 // - Interval([Interval(1, 1), Interval(2, 2)]) 213 if (Array.isArray(lo)) { 214 return new MatInterval(lo[0], lo[1]); 215 } 216 // - Interval(1) 217 return new MatInterval(lo, lo); 218 } else { 219 // This else is necessary even if jslint declares it as redundant 220 // possible cases: 221 // - Interval() 222 this.lo = this.hi = 0; 223 } 224 }; 225 226 JXG.extend(MatInterval.prototype, { 227 print: function () { 228 console.log("[", this.lo, this.hi, "]"); 229 }, 230 231 set: function (lo, hi) { 232 this.lo = lo; 233 this.hi = hi; 234 return this; 235 }, 236 237 bounded: function (lo, hi) { 238 return this.set(Mat.IntervalArithmetic.prev(lo), Mat.IntervalArithmetic.next(hi)); 239 }, 240 241 boundedSingleton: function (v) { 242 return this.bounded(v, v); 243 }, 244 245 assign: function (lo, hi) { 246 if (typeof lo !== "number" || typeof hi !== "number") { 247 throw new TypeError("JXG.Math.Interval#assign: arguments must be numbers"); 248 } 249 if (isNaN(lo) || isNaN(hi) || lo > hi) { 250 return this.setEmpty(); 251 } 252 return this.set(lo, hi); 253 }, 254 255 setEmpty: function () { 256 return this.set(Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY); 257 }, 258 259 setWhole: function () { 260 return this.set(Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY); 261 }, 262 263 open: function (lo, hi) { 264 return this.assign(Mat.IntervalArithmetic.next(lo), Mat.IntervalArithmetic.prev(hi)); 265 }, 266 267 halfOpenLeft: function (lo, hi) { 268 return this.assign(Mat.IntervalArithmetic.next(lo), hi); 269 }, 270 271 halfOpenRight: function (lo, hi) { 272 return this.assign(lo, Mat.IntervalArithmetic.prev(hi)); 273 }, 274 275 toArray: function () { 276 return [this.lo, this.hi]; 277 }, 278 279 clone: function () { 280 return new MatInterval().set(this.lo, this.hi); 281 } 282 }); 283 284 /** 285 * Object for interval arithmetics. 286 * @name JXG.Math.IntervalArithmetic 287 * @namespace 288 */ 289 JXG.Math.IntervalArithmetic = { 290 Interval: function (lo, hi) { 291 return new MatInterval(lo, hi); 292 }, 293 294 isInterval: function (i) { 295 return ( 296 i !== null && 297 typeof i === "object" && 298 typeof i.lo === "number" && 299 typeof i.hi === "number" 300 ); 301 }, 302 303 isSingleton: function (i) { 304 return i.lo === i.hi; 305 }, 306 307 /* 308 * Arithmetics 309 */ 310 311 /** 312 * Addition 313 * 314 * @param {JXG.Math.Interval|Number} x 315 * @param {JXG.Math.Interval|Number} y 316 * @returns JXG.Math.Interval 317 */ 318 add: function (x, y) { 319 if (Type.isNumber(x)) { 320 x = this.Interval(x); 321 } 322 if (Type.isNumber(y)) { 323 y = this.Interval(y); 324 } 325 return new MatInterval(this.addLo(x.lo, y.lo), this.addHi(x.hi, y.hi)); 326 }, 327 328 /** 329 * Subtraction 330 * 331 * @param {JXG.Math.Interval|Number} x 332 * @param {JXG.Math.Interval|Number} y 333 * @returns JXG.Math.Interval 334 */ 335 sub: function (x, y) { 336 if (Type.isNumber(x)) { 337 x = this.Interval(x); 338 } 339 if (Type.isNumber(y)) { 340 y = this.Interval(y); 341 } 342 return new MatInterval(this.subLo(x.lo, y.hi), this.subHi(x.hi, y.lo)); 343 }, 344 345 /** 346 * Multiplication 347 * 348 * @param {JXG.Math.Interval|Number} x 349 * @param {JXG.Math.Interval|Number} y 350 * @returns JXG.Math.Interval 351 */ 352 mul: function (x, y) { 353 var xl, xh, yl, yh, out; 354 355 if (Type.isNumber(x)) { 356 x = this.Interval(x); 357 } 358 if (Type.isNumber(y)) { 359 y = this.Interval(y); 360 } 361 362 if (this.isEmpty(x) || this.isEmpty(y)) { 363 return this.EMPTY.clone(); 364 } 365 xl = x.lo; 366 xh = x.hi; 367 yl = y.lo; 368 yh = y.hi; 369 out = new MatInterval(); 370 371 if (xl < 0) { 372 if (xh > 0) { 373 if (yl < 0) { 374 if (yh > 0) { 375 // mixed * mixed 376 out.lo = Math.min(this.mulLo(xl, yh), this.mulLo(xh, yl)); 377 out.hi = Math.max(this.mulHi(xl, yl), this.mulHi(xh, yh)); 378 } else { 379 // mixed * negative 380 out.lo = this.mulLo(xh, yl); 381 out.hi = this.mulHi(xl, yl); 382 } 383 } else { 384 if (yh > 0) { 385 // mixed * positive 386 out.lo = this.mulLo(xl, yh); 387 out.hi = this.mulHi(xh, yh); 388 } else { 389 // mixed * zero 390 out.lo = 0; 391 out.hi = 0; 392 } 393 } 394 } else { 395 if (yl < 0) { 396 if (yh > 0) { 397 // negative * mixed 398 out.lo = this.mulLo(xl, yh); 399 out.hi = this.mulHi(xl, yl); 400 } else { 401 // negative * negative 402 out.lo = this.mulLo(xh, yh); 403 out.hi = this.mulHi(xl, yl); 404 } 405 } else { 406 if (yh > 0) { 407 // negative * positive 408 out.lo = this.mulLo(xl, yh); 409 out.hi = this.mulHi(xh, yl); 410 } else { 411 // negative * zero 412 out.lo = 0; 413 out.hi = 0; 414 } 415 } 416 } 417 } else { 418 if (xh > 0) { 419 if (yl < 0) { 420 if (yh > 0) { 421 // positive * mixed 422 out.lo = this.mulLo(xh, yl); 423 out.hi = this.mulHi(xh, yh); 424 } else { 425 // positive * negative 426 out.lo = this.mulLo(xh, yl); 427 out.hi = this.mulHi(xl, yh); 428 } 429 } else { 430 if (yh > 0) { 431 // positive * positive 432 out.lo = this.mulLo(xl, yl); 433 out.hi = this.mulHi(xh, yh); 434 } else { 435 // positive * zero 436 out.lo = 0; 437 out.hi = 0; 438 } 439 } 440 } else { 441 // zero * any other value 442 out.lo = 0; 443 out.hi = 0; 444 } 445 } 446 return out; 447 }, 448 449 /** 450 * Division 451 * 452 * @param {JXG.Math.Interval|Number} x 453 * @param {JXG.Math.Interval|Number} y 454 * @returns JXG.Math.Interval 455 */ 456 div: function (x, y) { 457 if (Type.isNumber(x)) { 458 x = this.Interval(x); 459 } 460 if (Type.isNumber(y)) { 461 y = this.Interval(y); 462 } 463 464 if (this.isEmpty(x) || this.isEmpty(y)) { 465 return this.EMPTY.clone(); 466 } 467 if (this.zeroIn(y)) { 468 if (y.lo !== 0) { 469 if (y.hi !== 0) { 470 return this.divZero(x); 471 } 472 return this.divNegative(x, y.lo); 473 } 474 if (y.hi !== 0) { 475 return this.divPositive(x, y.hi); 476 } 477 return this.EMPTY.clone(); 478 } 479 return this.divNonZero(x, y); 480 }, 481 482 /** 483 * Return +x (i.e. identity) 484 * 485 * @param {JXG.Math.Interval} x 486 * @returns JXG.Math.Interval 487 */ 488 positive: function (x) { 489 return new MatInterval(x.lo, x.hi); 490 }, 491 492 /** 493 * Return -x 494 * 495 * @param {JXG.Math.Interval} x 496 * @returns JXG.Math.Interval 497 */ 498 negative: function (x) { 499 if (Type.isNumber(x)) { 500 return new MatInterval(-x); 501 } 502 return new MatInterval(-x.hi, -x.lo); 503 }, 504 505 /* 506 * Utils 507 */ 508 509 /** 510 * Test if interval is empty set. 511 * @param {JXG.Math.Interval} i 512 * @returns Boolean 513 */ 514 isEmpty: function (i) { 515 return i.lo > i.hi; 516 }, 517 518 /** 519 * Test if interval is (-Infinity, Infinity). 520 * @param {JXG.Math.Interval} i 521 * @returns Boolean 522 */ 523 isWhole: function (i) { 524 return i.lo === -Infinity && i.hi === Infinity; 525 }, 526 527 /** 528 * Test if interval contains 0. 529 * @param {JXG.Math.Interval} i 530 * @returns Boolean 531 */ 532 zeroIn: function (i) { 533 return this.hasValue(i, 0); 534 }, 535 536 /** 537 * Test if interval contains a specific value. 538 * @param {JXG.Math.Interval} i 539 * @param {Number} value 540 * @returns Boolean 541 */ 542 hasValue: function (i, value) { 543 if (this.isEmpty(i)) { 544 return false; 545 } 546 return i.lo <= value && value <= i.hi; 547 }, 548 549 /** 550 * Test if interval x contains interval y. 551 * @param {JXG.Math.Interval} x 552 * @param {JXG.Math.Interval} y 553 * @returns Boolean 554 */ 555 hasInterval: function (x, y) { 556 if (this.isEmpty(x)) { 557 return true; 558 } 559 return !this.isEmpty(y) && y.lo <= x.lo && x.hi <= y.hi; 560 }, 561 562 /** 563 * Test if intervals x and y have non-zero intersection. 564 * @param {JXG.Math.Interval} x 565 * @param {JXG.Math.Interval} y 566 * @returns Boolean 567 */ 568 intervalsOverlap: function (x, y) { 569 if (this.isEmpty(x) || this.isEmpty(y)) { 570 return false; 571 } 572 return (x.lo <= y.lo && y.lo <= x.hi) || (y.lo <= x.lo && x.lo <= y.hi); 573 }, 574 575 /* 576 * Division 577 */ 578 /** 579 * @private 580 * @param {JXG.Math.Interval} x 581 * @param {JXG.Math.Interval} y 582 * @returns JXG.Math.Interval 583 */ 584 divNonZero: function (x, y) { 585 var xl = x.lo, 586 xh = x.hi, 587 yl = y.lo, 588 yh = y.hi, 589 out = new MatInterval(); 590 591 if (xh < 0) { 592 if (yh < 0) { 593 out.lo = this.divLo(xh, yl); 594 out.hi = this.divHi(xl, yh); 595 } else { 596 out.lo = this.divLo(xl, yl); 597 out.hi = this.divHi(xh, yh); 598 } 599 } else if (xl < 0) { 600 if (yh < 0) { 601 out.lo = this.divLo(xh, yh); 602 out.hi = this.divHi(xl, yh); 603 } else { 604 out.lo = this.divLo(xl, yl); 605 out.hi = this.divHi(xh, yl); 606 } 607 } else { 608 if (yh < 0) { 609 out.lo = this.divLo(xh, yh); 610 out.hi = this.divHi(xl, yl); 611 } else { 612 out.lo = this.divLo(xl, yh); 613 out.hi = this.divHi(xh, yl); 614 } 615 } 616 return out; 617 }, 618 619 /** 620 * @private 621 * @param {JXG.Math.Interval} x 622 * @param {JXG.Math.Interval} y 623 * @returns JXG.Math.Interval 624 */ 625 divPositive: function (x, v) { 626 if (x.lo === 0 && x.hi === 0) { 627 return x; 628 } 629 630 if (this.zeroIn(x)) { 631 // mixed considering zero in both ends 632 return this.WHOLE; 633 } 634 635 if (x.hi < 0) { 636 // negative / v 637 return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(x.hi, v)); 638 } 639 // positive / v 640 return new MatInterval(this.divLo(x.lo, v), Number.POSITIVE_INFINITY); 641 }, 642 643 /** 644 * @private 645 * @param {JXG.Math.Interval} x 646 * @param {JXG.Math.Interval} y 647 * @returns JXG.Math.Interval 648 */ 649 divNegative: function (x, v) { 650 if (x.lo === 0 && x.hi === 0) { 651 return x; 652 } 653 654 if (this.zeroIn(x)) { 655 // mixed considering zero in both ends 656 return this.WHOLE; 657 } 658 659 if (x.hi < 0) { 660 // negative / v 661 return new MatInterval(this.divLo(x.hi, v), Number.POSITIVE_INFINITY); 662 } 663 // positive / v 664 return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(x.lo, v)); 665 }, 666 667 /** 668 * @private 669 * @param {JXG.Math.Interval} x 670 * @returns JXG.Math.Interval 671 */ 672 divZero: function (x) { 673 if (x.lo === 0 && x.hi === 0) { 674 return x; 675 } 676 return this.WHOLE; 677 }, 678 679 /* 680 * Algebra 681 */ 682 /** 683 * x mod y: x - n * y 684 * @param {JXG.Math.Interval|Number} x 685 * @param {JXG.Math.Interval|Number} y 686 * @returns JXG.Math.Interval 687 */ 688 fmod: function (x, y) { 689 var yb, n; 690 if (Type.isNumber(x)) { 691 x = this.Interval(x); 692 } 693 if (Type.isNumber(y)) { 694 y = this.Interval(y); 695 } 696 if (this.isEmpty(x) || this.isEmpty(y)) { 697 return this.EMPTY.clone(); 698 } 699 yb = x.lo < 0 ? y.lo : y.hi; 700 n = x.lo / yb; 701 if (n < 0) { 702 n = Math.ceil(n); 703 } else { 704 n = Math.floor(n); 705 } 706 // x mod y = x - n * y 707 return this.sub(x, this.mul(y, new MatInterval(n))); 708 }, 709 710 /** 711 * 1 / x 712 * @param {JXG.Math.Interval|Number} x 713 * @returns JXG.Math.Interval 714 */ 715 multiplicativeInverse: function (x) { 716 if (Type.isNumber(x)) { 717 x = this.Interval(x); 718 } 719 if (this.isEmpty(x)) { 720 return this.EMPTY.clone(); 721 } 722 if (this.zeroIn(x)) { 723 if (x.lo !== 0) { 724 if (x.hi !== 0) { 725 // [negative, positive] 726 return this.WHOLE; 727 } 728 // [negative, zero] 729 return new MatInterval(Number.NEGATIVE_INFINITY, this.divHi(1, x.lo)); 730 } 731 if (x.hi !== 0) { 732 // [zero, positive] 733 return new MatInterval(this.divLo(1, x.hi), Number.POSITIVE_INFINITY); 734 } 735 // [zero, zero] 736 return this.EMPTY.clone(); 737 } 738 // [positive, positive] 739 return new MatInterval(this.divLo(1, x.hi), this.divHi(1, x.lo)); 740 }, 741 742 /** 743 * x<sup>power</sup> 744 * @param {JXG.Math.Interval|Number} x 745 * @param {JXG.Math.Interval|Number} power 746 * @returns JXG.Math.Interval 747 */ 748 pow: function (x, power) { 749 var yl, yh; 750 751 if (Type.isNumber(x)) { 752 x = this.Interval(x); 753 } 754 if (this.isEmpty(x)) { 755 return this.EMPTY.clone(); 756 } 757 if (this.isInterval(power)) { 758 if (!this.isSingleton(power)) { 759 return this.EMPTY.clone(); 760 } 761 power = power.lo; 762 } 763 764 if (power === 0) { 765 if (x.lo === 0 && x.hi === 0) { 766 // 0^0 767 return this.EMPTY.clone(); 768 } 769 // x^0 770 return this.ONE.clone(); 771 } 772 if (power < 0) { 773 // compute [1 / x]^-power if power is negative 774 return this.pow(this.multiplicativeInverse(x), -power); 775 } 776 777 // power > 0 778 if (power % 1 === 0) { 779 // isSafeInteger(power) as boolean) { 780 // power is integer 781 if (x.hi < 0) { 782 // [negative, negative] 783 // assume that power is even so the operation will yield a positive interval 784 // if not then just switch the sign and order of the interval bounds 785 yl = this.powLo(-x.hi, power); 786 yh = this.powHi(-x.lo, power); 787 if ((power & 1) === 1) { 788 // odd power 789 return new MatInterval(-yh, -yl); 790 } 791 // even power 792 return new MatInterval(yl, yh); 793 } 794 if (x.lo < 0) { 795 // [negative, positive] 796 if ((power & 1) === 1) { 797 return new MatInterval(-this.powLo(-x.lo, power), this.powHi(x.hi, power)); 798 } 799 // even power means that any negative number will be zero (min value = 0) 800 // and the max value will be the max of x.lo^power, x.hi^power 801 return new MatInterval(0, this.powHi(Math.max(-x.lo, x.hi), power)); 802 } 803 // [positive, positive] 804 return new MatInterval(this.powLo(x.lo, power), this.powHi(x.hi, power)); 805 } 806 console.warn( 807 "power is not an integer, you should use nth-root instead, returning an empty interval" 808 ); 809 return this.EMPTY.clone(); 810 }, 811 812 /** 813 * sqrt(x) 814 * @param {JXG.Math.Interval|Number} x 815 * @returns JXG.Math.Interval 816 */ 817 sqrt: function (x) { 818 if (Type.isNumber(x)) { 819 x = this.Interval(x); 820 } 821 return this.nthRoot(x, 2); 822 }, 823 824 /** 825 * x<sup>1/n</sup> 826 * @param {JXG.Math.Interval|Number} x 827 * @param {Number} n 828 * @returns JXG.Math.Interval 829 */ 830 nthRoot: function (x, n) { 831 var power, yl, yh, yp, yn; 832 833 if (Type.isNumber(x)) { 834 x = this.Interval(x); 835 } 836 if (this.isEmpty(x) || n < 0) { 837 // compute 1 / x^-power if power is negative 838 return this.EMPTY.clone(); 839 } 840 841 // singleton interval check 842 if (this.isInterval(n)) { 843 if (!this.isSingleton(n)) { 844 return this.EMPTY.clone(); 845 } 846 n = n.lo; 847 } 848 849 power = 1 / n; 850 if (x.hi < 0) { 851 // [negative, negative] 852 //if ((isSafeInteger(n) as boolean) && (n & 1) === 1) { 853 if (n % 1 === 0 && (n & 1) === 1) { 854 // when n is odd we can always take the nth root 855 yl = this.powHi(-x.lo, power); 856 yh = this.powLo(-x.hi, power); 857 return new MatInterval(-yl, -yh); 858 } 859 860 // n is not odd therefore there's no nth root 861 return this.EMPTY.clone(); 862 } 863 if (x.lo < 0) { 864 // [negative, positive] 865 yp = this.powHi(x.hi, power); 866 // if ((isSafeInteger(n) as boolean) && (n & 1) === 1) { 867 if (n % 1 === 0 && (n & 1) === 1) { 868 // nth root of x.lo is possible (n is odd) 869 yn = -this.powHi(-x.lo, power); 870 return new MatInterval(yn, yp); 871 } 872 return new MatInterval(0, yp); 873 } 874 // [positive, positive] 875 return new MatInterval(this.powLo(x.lo, power), this.powHi(x.hi, power)); 876 }, 877 878 /* 879 * Misc 880 */ 881 /** 882 * 883 * @param {JXG.Math.Interval|Number} x 884 * @returns JXG.Math.Interval 885 */ 886 exp: function (x) { 887 if (Type.isNumber(x)) { 888 x = this.Interval(x); 889 } 890 if (this.isEmpty(x)) { 891 return this.EMPTY.clone(); 892 } 893 return new MatInterval(this.expLo(x.lo), this.expHi(x.hi)); 894 }, 895 896 /** 897 * Natural log 898 * @param {JXG.Math.Interval|Number} x 899 * @returns JXG.Math.Interval 900 */ 901 log: function (x) { 902 var l; 903 if (Type.isNumber(x)) { 904 x = this.Interval(x); 905 } 906 if (this.isEmpty(x)) { 907 return this.EMPTY.clone(); 908 } 909 l = x.lo <= 0 ? Number.NEGATIVE_INFINITY : this.logLo(x.lo); 910 return new MatInterval(l, this.logHi(x.hi)); 911 }, 912 913 /** 914 * Natural log, alias for {@link JXG.Math.IntervalArithmetic#log}. 915 * @param {JXG.Math.Interval|Number} x 916 * @returns JXG.Math.Interval 917 */ 918 ln: function (x) { 919 return this.log(x); 920 }, 921 922 // export const LOG_EXP_10 = this.log(new MatInterval(10, 10)) 923 // export const LOG_EXP_2 = log(new MatInterval(2, 2)) 924 /** 925 * Logarithm to base 10. 926 * @param {JXG.Math.Interval|Number} x 927 * @returns JXG.Math.Interval 928 */ 929 log10: function (x) { 930 if (this.isEmpty(x)) { 931 return this.EMPTY.clone(); 932 } 933 return this.div(this.log(x), this.log(new MatInterval(10, 10))); 934 }, 935 936 /** 937 * Logarithm to base 2. 938 * @param {JXG.Math.Interval|Number} x 939 * @returns JXG.Math.Interval 940 */ 941 log2: function (x) { 942 if (this.isEmpty(x)) { 943 return this.EMPTY.clone(); 944 } 945 return this.div(this.log(x), this.log(new MatInterval(2, 2))); 946 }, 947 948 /** 949 * Hull of intervals x and y 950 * @param {JXG.Math.Interval} x 951 * @param {JXG.Math.Interval} y 952 * @returns JXG.Math.Interval 953 */ 954 hull: function (x, y) { 955 var badX = this.isEmpty(x), 956 badY = this.isEmpty(y); 957 if (badX && badY) { 958 return this.EMPTY.clone(); 959 } 960 if (badX) { 961 return y.clone(); 962 } 963 if (badY) { 964 return x.clone(); 965 } 966 return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi)); 967 }, 968 969 /** 970 * Intersection of intervals x and y 971 * @param {JXG.Math.Interval} x 972 * @param {JXG.Math.Interval} y 973 * @returns JXG.Math.Interval 974 */ 975 intersection: function (x, y) { 976 var lo, hi; 977 if (this.isEmpty(x) || this.isEmpty(y)) { 978 return this.EMPTY.clone(); 979 } 980 lo = Math.max(x.lo, y.lo); 981 hi = Math.min(x.hi, y.hi); 982 if (lo <= hi) { 983 return new MatInterval(lo, hi); 984 } 985 return this.EMPTY.clone(); 986 }, 987 988 /** 989 * Union of overlapping intervals x and y 990 * @param {JXG.Math.Interval} x 991 * @param {JXG.Math.Interval} y 992 * @returns JXG.Math.Interval 993 */ 994 union: function (x, y) { 995 if (!this.intervalsOverlap(x, y)) { 996 throw new Error("Interval#unions do not overlap"); 997 } 998 return new MatInterval(Math.min(x.lo, y.lo), Math.max(x.hi, y.hi)); 999 }, 1000 1001 /** 1002 * Difference of overlapping intervals x and y 1003 * @param {JXG.Math.Interval} x 1004 * @param {JXG.Math.Interval} y 1005 * @returns JXG.Math.Interval 1006 */ 1007 difference: function (x, y) { 1008 if (this.isEmpty(x) || this.isWhole(y)) { 1009 return this.EMPTY.clone(); 1010 } 1011 if (this.intervalsOverlap(x, y)) { 1012 if (x.lo < y.lo && y.hi < x.hi) { 1013 // difference creates multiple subsets 1014 throw new Error("Interval.difference: difference creates multiple intervals"); 1015 } 1016 1017 // handle corner cases first 1018 if ((y.lo <= x.lo && y.hi === Infinity) || (y.hi >= x.hi && y.lo === -Infinity)) { 1019 return this.EMPTY.clone(); 1020 } 1021 1022 // NOTE: empty interval is handled automatically 1023 // e.g. 1024 // 1025 // n = difference([0,1], [0,1]) // n = Interval(next(1), 1) = EMPTY 1026 // isEmpty(n) === true 1027 // 1028 if (y.lo <= x.lo) { 1029 return new MatInterval().halfOpenLeft(y.hi, x.hi); 1030 } 1031 1032 // y.hi >= x.hi 1033 return new MatInterval().halfOpenRight(x.lo, y.lo); 1034 } 1035 return x.clone(); 1036 }, 1037 1038 /** 1039 * @param {JXG.Math.Interval} x 1040 * @returns JXG.Math.Interval 1041 */ 1042 width: function (x) { 1043 if (this.isEmpty(x)) { 1044 return 0; 1045 } 1046 return this.subHi(x.hi, x.lo); 1047 }, 1048 1049 /** 1050 * @param {JXG.Math.Interval} x 1051 * @returns JXG.Math.Interval 1052 */ 1053 abs: function (x) { 1054 if (Type.isNumber(x)) { 1055 x = this.Interval(x); 1056 } 1057 if (this.isEmpty(x)) { 1058 return this.EMPTY.clone(); 1059 } 1060 if (x.lo >= 0) { 1061 return x.clone(); 1062 } 1063 if (x.hi <= 0) { 1064 return this.negative(x); 1065 } 1066 return new MatInterval(0, Math.max(-x.lo, x.hi)); 1067 }, 1068 1069 /** 1070 * @param {JXG.Math.Interval} x 1071 * @param {JXG.Math.Interval} y 1072 * @returns JXG.Math.Interval 1073 */ 1074 max: function (x, y) { 1075 var badX = this.isEmpty(x), 1076 badY = this.isEmpty(y); 1077 if (badX && badY) { 1078 return this.EMPTY.clone(); 1079 } 1080 if (badX) { 1081 return y.clone(); 1082 } 1083 if (badY) { 1084 return x.clone(); 1085 } 1086 return new MatInterval(Math.max(x.lo, y.lo), Math.max(x.hi, y.hi)); 1087 }, 1088 1089 /** 1090 * @param {JXG.Math.Interval} x 1091 * @param {JXG.Math.Interval} y 1092 * @returns JXG.Math.Interval 1093 */ 1094 min: function (x, y) { 1095 var badX = this.isEmpty(x), 1096 badY = this.isEmpty(y); 1097 if (badX && badY) { 1098 return this.EMPTY.clone(); 1099 } 1100 if (badX) { 1101 return y.clone(); 1102 } 1103 if (badY) { 1104 return x.clone(); 1105 } 1106 return new MatInterval(Math.min(x.lo, y.lo), Math.min(x.hi, y.hi)); 1107 }, 1108 1109 /* 1110 * Trigonometric 1111 */ 1112 onlyInfinity: function (x) { 1113 return !isFinite(x.lo) && x.lo === x.hi; 1114 }, 1115 1116 _handleNegative: function (interval) { 1117 var n; 1118 if (interval.lo < 0) { 1119 if (interval.lo === -Infinity) { 1120 interval.lo = 0; 1121 interval.hi = Infinity; 1122 } else { 1123 n = Math.ceil(-interval.lo / this.piTwiceLow); 1124 interval.lo += this.piTwiceLow * n; 1125 interval.hi += this.piTwiceLow * n; 1126 } 1127 } 1128 return interval; 1129 }, 1130 1131 /** 1132 * @param {JXG.Math.Interval} x 1133 * @returns JXG.Math.Interval 1134 */ 1135 cos: function (x) { 1136 var cache, pi2, t, cosv, lo, hi, rlo, rhi; 1137 1138 if (this.isEmpty(x) || this.onlyInfinity(x)) { 1139 return this.EMPTY.clone(); 1140 } 1141 1142 // create a clone of `x` because the clone is going to be modified 1143 cache = new MatInterval().set(x.lo, x.hi); 1144 this._handleNegative(cache); 1145 1146 pi2 = this.PI_TWICE; 1147 t = this.fmod(cache, pi2); 1148 if (this.width(t) >= pi2.lo) { 1149 return new MatInterval(-1, 1); 1150 } 1151 1152 // when t.lo > pi it's the same as 1153 // -cos(t - pi) 1154 if (t.lo >= this.piHigh) { 1155 cosv = this.cos(this.sub(t, this.PI)); 1156 return this.negative(cosv); 1157 } 1158 1159 lo = t.lo; 1160 hi = t.hi; 1161 rlo = this.cosLo(hi); 1162 rhi = this.cosHi(lo); 1163 // it's ensured that t.lo < pi and that t.lo >= 0 1164 if (hi <= this.piLow) { 1165 // when t.hi < pi 1166 // [cos(t.lo), cos(t.hi)] 1167 return new MatInterval(rlo, rhi); 1168 } 1169 if (hi <= pi2.lo) { 1170 // when t.hi < 2pi 1171 // [-1, max(cos(t.lo), cos(t.hi))] 1172 return new MatInterval(-1, Math.max(rlo, rhi)); 1173 } 1174 // t.lo < pi and t.hi > 2pi 1175 return new MatInterval(-1, 1); 1176 }, 1177 1178 /** 1179 * @param {JXG.Math.Interval} x 1180 * @returns JXG.Math.Interval 1181 */ 1182 sin: function (x) { 1183 if (this.isEmpty(x) || this.onlyInfinity(x)) { 1184 return this.EMPTY.clone(); 1185 } 1186 return this.cos(this.sub(x, this.PI_HALF)); 1187 }, 1188 1189 /** 1190 * @param {JXG.Math.Interval} x 1191 * @returns JXG.Math.Interval 1192 */ 1193 tan: function (x) { 1194 var cache, t, pi; 1195 if (this.isEmpty(x) || this.onlyInfinity(x)) { 1196 return this.EMPTY.clone(); 1197 } 1198 1199 // create a clone of `x` because the clone is going to be modified 1200 cache = new MatInterval().set(x.lo, x.hi); 1201 this._handleNegative(cache); 1202 1203 pi = this.PI; 1204 t = this.fmod(cache, pi); 1205 if (t.lo >= this.piHalfLow) { 1206 t = this.sub(t, pi); 1207 } 1208 if (t.lo <= -this.piHalfLow || t.hi >= this.piHalfLow) { 1209 return this.WHOLE.clone(); 1210 } 1211 return new MatInterval(this.tanLo(t.lo), this.tanHi(t.hi)); 1212 }, 1213 1214 /** 1215 * @param {JXG.Math.Interval} x 1216 * @returns JXG.Math.Interval 1217 */ 1218 asin: function (x) { 1219 var lo, hi; 1220 if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) { 1221 return this.EMPTY.clone(); 1222 } 1223 lo = x.lo <= -1 ? -this.piHalfHigh : this.asinLo(x.lo); 1224 hi = x.hi >= 1 ? this.piHalfHigh : this.asinHi(x.hi); 1225 return new MatInterval(lo, hi); 1226 }, 1227 1228 /** 1229 * @param {JXG.Math.Interval} x 1230 * @returns JXG.Math.Interval 1231 */ 1232 acos: function (x) { 1233 var lo, hi; 1234 if (this.isEmpty(x) || x.hi < -1 || x.lo > 1) { 1235 return this.EMPTY.clone(); 1236 } 1237 lo = x.hi >= 1 ? 0 : this.acosLo(x.hi); 1238 hi = x.lo <= -1 ? this.piHigh : this.acosHi(x.lo); 1239 return new MatInterval(lo, hi); 1240 }, 1241 1242 /** 1243 * @param {JXG.Math.Interval} x 1244 * @returns JXG.Math.Interval 1245 */ 1246 atan: function (x) { 1247 if (this.isEmpty(x)) { 1248 return this.EMPTY.clone(); 1249 } 1250 return new MatInterval(this.atanLo(x.lo), this.atanHi(x.hi)); 1251 }, 1252 1253 /** 1254 * @param {JXG.Math.Interval} x 1255 * @returns JXG.Math.Interval 1256 */ 1257 sinh: function (x) { 1258 if (this.isEmpty(x)) { 1259 return this.EMPTY.clone(); 1260 } 1261 return new MatInterval(this.sinhLo(x.lo), this.sinhHi(x.hi)); 1262 }, 1263 1264 /** 1265 * @param {JXG.Math.Interval} x 1266 * @returns JXG.Math.Interval 1267 */ 1268 cosh: function (x) { 1269 if (this.isEmpty(x)) { 1270 return this.EMPTY.clone(); 1271 } 1272 if (x.hi < 0) { 1273 return new MatInterval(this.coshLo(x.hi), this.coshHi(x.lo)); 1274 } 1275 if (x.lo >= 0) { 1276 return new MatInterval(this.coshLo(x.lo), this.coshHi(x.hi)); 1277 } 1278 return new MatInterval(1, this.coshHi(-x.lo > x.hi ? x.lo : x.hi)); 1279 }, 1280 1281 /** 1282 * @param {JXG.Math.Interval} x 1283 * @returns JXG.Math.Interval 1284 */ 1285 tanh: function (x) { 1286 if (this.isEmpty(x)) { 1287 return this.EMPTY.clone(); 1288 } 1289 return new MatInterval(this.tanhLo(x.lo), this.tanhHi(x.hi)); 1290 }, 1291 1292 /* 1293 * Relational 1294 */ 1295 1296 /** 1297 * @param {JXG.Math.Interval} x 1298 * @param {JXG.Math.Interval} y 1299 * @returns Boolean 1300 */ 1301 equal: function (x, y) { 1302 if (this.isEmpty(x)) { 1303 return this.isEmpty(y); 1304 } 1305 return !this.isEmpty(y) && x.lo === y.lo && x.hi === y.hi; 1306 }, 1307 1308 // almostEqual: function(x, y): void { 1309 // x = Array.isArray(x) ? x : x.toArray(); 1310 // y = Array.isArray(y) ? y : y.toArray(); 1311 // assertEps(x[0], y[0]) 1312 // assertEps(x[1], y[1]) 1313 // }, 1314 1315 /** 1316 * @param {JXG.Math.Interval} x 1317 * @param {JXG.Math.Interval} y 1318 * @returns Boolean 1319 */ 1320 notEqual: function (x, y) { 1321 if (this.isEmpty(x)) { 1322 return !this.isEmpty(y); 1323 } 1324 return this.isEmpty(y) || x.hi < y.lo || x.lo > y.hi; 1325 }, 1326 1327 /** 1328 * @param {JXG.Math.Interval} x 1329 * @param {JXG.Math.Interval} y 1330 * @returns Boolean 1331 */ 1332 lt: function (x, y) { 1333 if (Type.isNumber(x)) { 1334 x = this.Interval(x); 1335 } 1336 if (Type.isNumber(y)) { 1337 y = this.Interval(y); 1338 } 1339 if (this.isEmpty(x) || this.isEmpty(y)) { 1340 return false; 1341 } 1342 return x.hi < y.lo; 1343 }, 1344 1345 /** 1346 * @param {JXG.Math.Interval} x 1347 * @param {JXG.Math.Interval} y 1348 * @returns Boolean 1349 */ 1350 gt: function (x, y) { 1351 if (Type.isNumber(x)) { 1352 x = this.Interval(x); 1353 } 1354 if (Type.isNumber(y)) { 1355 y = this.Interval(y); 1356 } 1357 if (this.isEmpty(x) || this.isEmpty(y)) { 1358 return false; 1359 } 1360 return x.lo > y.hi; 1361 }, 1362 1363 /** 1364 * @param {JXG.Math.Interval} x 1365 * @param {JXG.Math.Interval} y 1366 * @returns Boolean 1367 */ 1368 leq: function (x, y) { 1369 if (Type.isNumber(x)) { 1370 x = this.Interval(x); 1371 } 1372 if (Type.isNumber(y)) { 1373 y = this.Interval(y); 1374 } 1375 if (this.isEmpty(x) || this.isEmpty(y)) { 1376 return false; 1377 } 1378 return x.hi <= y.lo; 1379 }, 1380 1381 /** 1382 * @param {JXG.Math.Interval} x 1383 * @param {JXG.Math.Interval} y 1384 * @returns Boolean 1385 */ 1386 geq: function (x, y) { 1387 if (Type.isNumber(x)) { 1388 x = this.Interval(x); 1389 } 1390 if (Type.isNumber(y)) { 1391 y = this.Interval(y); 1392 } 1393 if (this.isEmpty(x) || this.isEmpty(y)) { 1394 return false; 1395 } 1396 return x.lo >= y.hi; 1397 }, 1398 1399 /* 1400 * Constants 1401 */ 1402 piLow: (3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30), 1403 piHigh: (3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30), 1404 piHalfLow: ((3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30)) * 0.5, 1405 piHalfHigh: ((3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30)) * 0.5, 1406 piTwiceLow: ((3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30)) * 2, 1407 piTwiceHigh: ((3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30)) * 2, 1408 1409 /* 1410 * Round 1411 * Rounding functions for numbers 1412 */ 1413 identity: function (v) { 1414 return v; 1415 }, 1416 1417 _prev: function (v) { 1418 if (v === Infinity) { 1419 return v; 1420 } 1421 return this.nextafter(v, -Infinity); 1422 }, 1423 1424 _next: function (v) { 1425 if (v === -Infinity) { 1426 return v; 1427 } 1428 return this.nextafter(v, Infinity); 1429 }, 1430 1431 prev: function (v) { 1432 return this._prev(v); 1433 }, 1434 1435 next: function (v) { 1436 return this._next(v); 1437 }, 1438 1439 toInteger: function (x) { 1440 return x < 0 ? Math.ceil(x) : Math.floor(x); 1441 }, 1442 1443 addLo: function (x, y) { 1444 return this.prev(x + y); 1445 }, 1446 addHi: function (x, y) { 1447 return this.next(x + y); 1448 }, 1449 subLo: function (x, y) { 1450 return this.prev(x - y); 1451 }, 1452 subHi: function (x, y) { 1453 return this.next(x - y); 1454 }, 1455 mulLo: function (x, y) { 1456 return this.prev(x * y); 1457 }, 1458 mulHi: function (x, y) { 1459 return this.next(x * y); 1460 }, 1461 divLo: function (x, y) { 1462 return this.prev(x / y); 1463 }, 1464 divHi: function (x, y) { 1465 return this.next(x / y); 1466 }, 1467 intLo: function (x) { 1468 return this.toInteger(this.prev(x)); 1469 }, 1470 intHi: function (x) { 1471 return this.toInteger(this.next(x)); 1472 }, 1473 logLo: function (x) { 1474 return this.prev(Math.log(x)); 1475 }, 1476 logHi: function (x) { 1477 return this.next(Math.log(x)); 1478 }, 1479 expLo: function (x) { 1480 return this.prev(Math.exp(x)); 1481 }, 1482 expHi: function (x) { 1483 return this.next(Math.exp(x)); 1484 }, 1485 sinLo: function (x) { 1486 return this.prev(Math.sin(x)); 1487 }, 1488 sinHi: function (x) { 1489 return this.next(Math.sin(x)); 1490 }, 1491 cosLo: function (x) { 1492 return this.prev(Math.cos(x)); 1493 }, 1494 cosHi: function (x) { 1495 return this.next(Math.cos(x)); 1496 }, 1497 tanLo: function (x) { 1498 return this.prev(Math.tan(x)); 1499 }, 1500 tanHi: function (x) { 1501 return this.next(Math.tan(x)); 1502 }, 1503 asinLo: function (x) { 1504 return this.prev(Math.asin(x)); 1505 }, 1506 asinHi: function (x) { 1507 return this.next(Math.asin(x)); 1508 }, 1509 acosLo: function (x) { 1510 return this.prev(Math.acos(x)); 1511 }, 1512 acosHi: function (x) { 1513 return this.next(Math.acos(x)); 1514 }, 1515 atanLo: function (x) { 1516 return this.prev(Math.atan(x)); 1517 }, 1518 atanHi: function (x) { 1519 return this.next(Math.atan(x)); 1520 }, 1521 sinhLo: function (x) { 1522 return this.prev(Mat.sinh(x)); 1523 }, 1524 sinhHi: function (x) { 1525 return this.next(Mat.sinh(x)); 1526 }, 1527 coshLo: function (x) { 1528 return this.prev(Mat.cosh(x)); 1529 }, 1530 coshHi: function (x) { 1531 return this.next(Mat.cosh(x)); 1532 }, 1533 tanhLo: function (x) { 1534 return this.prev(Mat.tanh(x)); 1535 }, 1536 tanhHi: function (x) { 1537 return this.next(Mat.tanh(x)); 1538 }, 1539 sqrtLo: function (x) { 1540 return this.prev(Math.sqrt(x)); 1541 }, 1542 sqrtHi: function (x) { 1543 return this.next(Math.sqrt(x)); 1544 }, 1545 1546 powLo: function (x, power) { 1547 var y; 1548 if (power % 1 !== 0) { 1549 // power has decimals 1550 return this.prev(Math.pow(x, power)); 1551 } 1552 1553 y = (power & 1) === 1 ? x : 1; 1554 power >>= 1; 1555 while (power > 0) { 1556 x = this.mulLo(x, x); 1557 if ((power & 1) === 1) { 1558 y = this.mulLo(x, y); 1559 } 1560 power >>= 1; 1561 } 1562 return y; 1563 }, 1564 1565 powHi: function (x, power) { 1566 var y; 1567 if (power % 1 !== 0) { 1568 // power has decimals 1569 return this.next(Math.pow(x, power)); 1570 } 1571 1572 y = (power & 1) === 1 ? x : 1; 1573 power >>= 1; 1574 while (power > 0) { 1575 x = this.mulHi(x, x); 1576 if ((power & 1) === 1) { 1577 y = this.mulHi(x, y); 1578 } 1579 power >>= 1; 1580 } 1581 return y; 1582 }, 1583 1584 /** 1585 * @ignore 1586 * @private 1587 */ 1588 disable: function () { 1589 this.next = this.prev = this.identity; 1590 }, 1591 1592 /** 1593 * @ignore 1594 * @private 1595 */ 1596 enable: function () { 1597 this.prev = function (v) { 1598 return this._prev(v); 1599 }; 1600 1601 this.next = function (v) { 1602 return this._next(v); 1603 }; 1604 }, 1605 1606 /* 1607 * nextafter 1608 */ 1609 SMALLEST_DENORM: Math.pow(2, -1074), 1610 UINT_MAX: -1 >>> 0, 1611 1612 nextafter: function (x, y) { 1613 var lo, hi; 1614 1615 if (isNaN(x) || isNaN(y)) { 1616 return NaN; 1617 } 1618 if (x === y) { 1619 return x; 1620 } 1621 if (x === 0) { 1622 if (y < 0) { 1623 return -this.SMALLEST_DENORM; 1624 } 1625 return this.SMALLEST_DENORM; 1626 } 1627 hi = doubleBits.hi(x); 1628 lo = doubleBits.lo(x); 1629 if (y > x === x > 0) { 1630 if (lo === this.UINT_MAX) { 1631 hi += 1; 1632 lo = 0; 1633 } else { 1634 lo += 1; 1635 } 1636 } else { 1637 if (lo === 0) { 1638 lo = this.UINT_MAX; 1639 hi -= 1; 1640 } else { 1641 lo -= 1; 1642 } 1643 } 1644 return doubleBits.pack(lo, hi); 1645 } 1646 }; 1647 1648 JXG.Math.IntervalArithmetic.PI = new MatInterval( 1649 Mat.IntervalArithmetic.piLow, 1650 Mat.IntervalArithmetic.piHigh 1651 ); 1652 JXG.Math.IntervalArithmetic.PI_HALF = new MatInterval( 1653 Mat.IntervalArithmetic.piHalfLow, 1654 Mat.IntervalArithmetic.piHalfHigh 1655 ); 1656 JXG.Math.IntervalArithmetic.PI_TWICE = new MatInterval( 1657 Mat.IntervalArithmetic.piTwiceLow, 1658 Mat.IntervalArithmetic.piTwiceHigh 1659 ); 1660 JXG.Math.IntervalArithmetic.ZERO = new MatInterval(0); 1661 JXG.Math.IntervalArithmetic.ONE = new MatInterval(1); 1662 JXG.Math.IntervalArithmetic.WHOLE = new MatInterval().setWhole(); 1663 JXG.Math.IntervalArithmetic.EMPTY = new MatInterval().setEmpty(); 1664 1665 export default JXG.Math.IntervalArithmetic; 1666