1 /* 2 Copyright 2008-2024 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.js"; 34 import Mat from "./math.js"; 35 import Type from "../utils/type.js"; 36 37 JXG.Math.DoubleBits = function () { 38 var DOUBLE_VIEW = new Float64Array(1), 39 UINT_VIEW = new Uint32Array(DOUBLE_VIEW.buffer), 40 doubleBitsLE, 41 toDoubleLE, 42 lowUintLE, 43 highUintLE, 44 // doubleBits, 45 // toDouble, 46 // lowUint, 47 // highUint, 48 // hasTypedArrays = false, 49 doubleBitsBE, 50 toDoubleBE, 51 lowUintBE, 52 highUintBE; 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 acot: function (x) { 1247 if (this.isEmpty(x)) { 1248 return this.EMPTY.clone(); 1249 } 1250 return new MatInterval(this.acotLo(x.lo), this.acotHi(x.hi)); 1251 }, 1252 1253 /** 1254 * @param {JXG.Math.Interval} x 1255 * @returns JXG.Math.Interval 1256 */ 1257 atan: function (x) { 1258 if (this.isEmpty(x)) { 1259 return this.EMPTY.clone(); 1260 } 1261 return new MatInterval(this.atanLo(x.lo), this.atanHi(x.hi)); 1262 }, 1263 1264 /** 1265 * @param {JXG.Math.Interval} x 1266 * @returns JXG.Math.Interval 1267 */ 1268 sinh: function (x) { 1269 if (this.isEmpty(x)) { 1270 return this.EMPTY.clone(); 1271 } 1272 return new MatInterval(this.sinhLo(x.lo), this.sinhHi(x.hi)); 1273 }, 1274 1275 /** 1276 * @param {JXG.Math.Interval} x 1277 * @returns JXG.Math.Interval 1278 */ 1279 cosh: function (x) { 1280 if (this.isEmpty(x)) { 1281 return this.EMPTY.clone(); 1282 } 1283 if (x.hi < 0) { 1284 return new MatInterval(this.coshLo(x.hi), this.coshHi(x.lo)); 1285 } 1286 if (x.lo >= 0) { 1287 return new MatInterval(this.coshLo(x.lo), this.coshHi(x.hi)); 1288 } 1289 return new MatInterval(1, this.coshHi(-x.lo > x.hi ? x.lo : x.hi)); 1290 }, 1291 1292 /** 1293 * @param {JXG.Math.Interval} x 1294 * @returns JXG.Math.Interval 1295 */ 1296 tanh: function (x) { 1297 if (this.isEmpty(x)) { 1298 return this.EMPTY.clone(); 1299 } 1300 return new MatInterval(this.tanhLo(x.lo), this.tanhHi(x.hi)); 1301 }, 1302 1303 /* 1304 * Relational 1305 */ 1306 1307 /** 1308 * @param {JXG.Math.Interval} x 1309 * @param {JXG.Math.Interval} y 1310 * @returns Boolean 1311 */ 1312 equal: function (x, y) { 1313 if (this.isEmpty(x)) { 1314 return this.isEmpty(y); 1315 } 1316 return !this.isEmpty(y) && x.lo === y.lo && x.hi === y.hi; 1317 }, 1318 1319 // almostEqual: function(x, y): void { 1320 // x = Array.isArray(x) ? x : x.toArray(); 1321 // y = Array.isArray(y) ? y : y.toArray(); 1322 // assertEps(x[0], y[0]) 1323 // assertEps(x[1], y[1]) 1324 // }, 1325 1326 /** 1327 * @param {JXG.Math.Interval} x 1328 * @param {JXG.Math.Interval} y 1329 * @returns Boolean 1330 */ 1331 notEqual: function (x, y) { 1332 if (this.isEmpty(x)) { 1333 return !this.isEmpty(y); 1334 } 1335 return this.isEmpty(y) || x.hi < y.lo || x.lo > y.hi; 1336 }, 1337 1338 /** 1339 * @param {JXG.Math.Interval} x 1340 * @param {JXG.Math.Interval} y 1341 * @returns Boolean 1342 */ 1343 lt: function (x, y) { 1344 if (Type.isNumber(x)) { 1345 x = this.Interval(x); 1346 } 1347 if (Type.isNumber(y)) { 1348 y = this.Interval(y); 1349 } 1350 if (this.isEmpty(x) || this.isEmpty(y)) { 1351 return false; 1352 } 1353 return x.hi < y.lo; 1354 }, 1355 1356 /** 1357 * @param {JXG.Math.Interval} x 1358 * @param {JXG.Math.Interval} y 1359 * @returns Boolean 1360 */ 1361 gt: function (x, y) { 1362 if (Type.isNumber(x)) { 1363 x = this.Interval(x); 1364 } 1365 if (Type.isNumber(y)) { 1366 y = this.Interval(y); 1367 } 1368 if (this.isEmpty(x) || this.isEmpty(y)) { 1369 return false; 1370 } 1371 return x.lo > y.hi; 1372 }, 1373 1374 /** 1375 * @param {JXG.Math.Interval} x 1376 * @param {JXG.Math.Interval} y 1377 * @returns Boolean 1378 */ 1379 leq: function (x, y) { 1380 if (Type.isNumber(x)) { 1381 x = this.Interval(x); 1382 } 1383 if (Type.isNumber(y)) { 1384 y = this.Interval(y); 1385 } 1386 if (this.isEmpty(x) || this.isEmpty(y)) { 1387 return false; 1388 } 1389 return x.hi <= y.lo; 1390 }, 1391 1392 /** 1393 * @param {JXG.Math.Interval} x 1394 * @param {JXG.Math.Interval} y 1395 * @returns Boolean 1396 */ 1397 geq: function (x, y) { 1398 if (Type.isNumber(x)) { 1399 x = this.Interval(x); 1400 } 1401 if (Type.isNumber(y)) { 1402 y = this.Interval(y); 1403 } 1404 if (this.isEmpty(x) || this.isEmpty(y)) { 1405 return false; 1406 } 1407 return x.lo >= y.hi; 1408 }, 1409 1410 /* 1411 * Constants 1412 */ 1413 piLow: (3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30), 1414 piHigh: (3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30), 1415 piHalfLow: ((3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30)) * 0.5, 1416 piHalfHigh: ((3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30)) * 0.5, 1417 piTwiceLow: ((3373259426.0 + 273688.0 / (1 << 21)) / (1 << 30)) * 2, 1418 piTwiceHigh: ((3373259426.0 + 273689.0 / (1 << 21)) / (1 << 30)) * 2, 1419 1420 /* 1421 * Round 1422 * Rounding functions for numbers 1423 */ 1424 identity: function (v) { 1425 return v; 1426 }, 1427 1428 _prev: function (v) { 1429 if (v === Infinity) { 1430 return v; 1431 } 1432 return this.nextafter(v, -Infinity); 1433 }, 1434 1435 _next: function (v) { 1436 if (v === -Infinity) { 1437 return v; 1438 } 1439 return this.nextafter(v, Infinity); 1440 }, 1441 1442 prev: function (v) { 1443 return this._prev(v); 1444 }, 1445 1446 next: function (v) { 1447 return this._next(v); 1448 }, 1449 1450 toInteger: function (x) { 1451 return x < 0 ? Math.ceil(x) : Math.floor(x); 1452 }, 1453 1454 addLo: function (x, y) { 1455 return this.prev(x + y); 1456 }, 1457 addHi: function (x, y) { 1458 return this.next(x + y); 1459 }, 1460 subLo: function (x, y) { 1461 return this.prev(x - y); 1462 }, 1463 subHi: function (x, y) { 1464 return this.next(x - y); 1465 }, 1466 mulLo: function (x, y) { 1467 return this.prev(x * y); 1468 }, 1469 mulHi: function (x, y) { 1470 return this.next(x * y); 1471 }, 1472 divLo: function (x, y) { 1473 return this.prev(x / y); 1474 }, 1475 divHi: function (x, y) { 1476 return this.next(x / y); 1477 }, 1478 intLo: function (x) { 1479 return this.toInteger(this.prev(x)); 1480 }, 1481 intHi: function (x) { 1482 return this.toInteger(this.next(x)); 1483 }, 1484 logLo: function (x) { 1485 return this.prev(Math.log(x)); 1486 }, 1487 logHi: function (x) { 1488 return this.next(Math.log(x)); 1489 }, 1490 expLo: function (x) { 1491 return this.prev(Math.exp(x)); 1492 }, 1493 expHi: function (x) { 1494 return this.next(Math.exp(x)); 1495 }, 1496 sinLo: function (x) { 1497 return this.prev(Math.sin(x)); 1498 }, 1499 sinHi: function (x) { 1500 return this.next(Math.sin(x)); 1501 }, 1502 cosLo: function (x) { 1503 return this.prev(Math.cos(x)); 1504 }, 1505 cosHi: function (x) { 1506 return this.next(Math.cos(x)); 1507 }, 1508 tanLo: function (x) { 1509 return this.prev(Math.tan(x)); 1510 }, 1511 tanHi: function (x) { 1512 return this.next(Math.tan(x)); 1513 }, 1514 asinLo: function (x) { 1515 return this.prev(Math.asin(x)); 1516 }, 1517 asinHi: function (x) { 1518 return this.next(Math.asin(x)); 1519 }, 1520 acosLo: function (x) { 1521 return this.prev(Math.acos(x)); 1522 }, 1523 acosHi: function (x) { 1524 return this.next(Math.acos(x)); 1525 }, 1526 acotLo: function (x) { 1527 return this.prev(Mat.acot(x)); 1528 }, 1529 acotHi: function (x) { 1530 return this.next(Mat.acot(x)); 1531 }, 1532 atanLo: function (x) { 1533 return this.prev(Math.atan(x)); 1534 }, 1535 atanHi: function (x) { 1536 return this.next(Math.atan(x)); 1537 }, 1538 sinhLo: function (x) { 1539 return this.prev(Mat.sinh(x)); 1540 }, 1541 sinhHi: function (x) { 1542 return this.next(Mat.sinh(x)); 1543 }, 1544 coshLo: function (x) { 1545 return this.prev(Mat.cosh(x)); 1546 }, 1547 coshHi: function (x) { 1548 return this.next(Mat.cosh(x)); 1549 }, 1550 tanhLo: function (x) { 1551 return this.prev(Mat.tanh(x)); 1552 }, 1553 tanhHi: function (x) { 1554 return this.next(Mat.tanh(x)); 1555 }, 1556 sqrtLo: function (x) { 1557 return this.prev(Math.sqrt(x)); 1558 }, 1559 sqrtHi: function (x) { 1560 return this.next(Math.sqrt(x)); 1561 }, 1562 1563 powLo: function (x, power) { 1564 var y; 1565 if (power % 1 !== 0) { 1566 // power has decimals 1567 return this.prev(Math.pow(x, power)); 1568 } 1569 1570 y = (power & 1) === 1 ? x : 1; 1571 power >>= 1; 1572 while (power > 0) { 1573 x = this.mulLo(x, x); 1574 if ((power & 1) === 1) { 1575 y = this.mulLo(x, y); 1576 } 1577 power >>= 1; 1578 } 1579 return y; 1580 }, 1581 1582 powHi: function (x, power) { 1583 var y; 1584 if (power % 1 !== 0) { 1585 // power has decimals 1586 return this.next(Math.pow(x, power)); 1587 } 1588 1589 y = (power & 1) === 1 ? x : 1; 1590 power >>= 1; 1591 while (power > 0) { 1592 x = this.mulHi(x, x); 1593 if ((power & 1) === 1) { 1594 y = this.mulHi(x, y); 1595 } 1596 power >>= 1; 1597 } 1598 return y; 1599 }, 1600 1601 /** 1602 * @ignore 1603 * @private 1604 */ 1605 disable: function () { 1606 this.next = this.prev = this.identity; 1607 }, 1608 1609 /** 1610 * @ignore 1611 * @private 1612 */ 1613 enable: function () { 1614 this.prev = function (v) { 1615 return this._prev(v); 1616 }; 1617 1618 this.next = function (v) { 1619 return this._next(v); 1620 }; 1621 }, 1622 1623 /* 1624 * nextafter 1625 */ 1626 SMALLEST_DENORM: Math.pow(2, -1074), 1627 UINT_MAX: -1 >>> 0, 1628 1629 nextafter: function (x, y) { 1630 var lo, hi; 1631 1632 if (isNaN(x) || isNaN(y)) { 1633 return NaN; 1634 } 1635 if (x === y) { 1636 return x; 1637 } 1638 if (x === 0) { 1639 if (y < 0) { 1640 return -this.SMALLEST_DENORM; 1641 } 1642 return this.SMALLEST_DENORM; 1643 } 1644 hi = doubleBits.hi(x); 1645 lo = doubleBits.lo(x); 1646 if (y > x === x > 0) { 1647 if (lo === this.UINT_MAX) { 1648 hi += 1; 1649 lo = 0; 1650 } else { 1651 lo += 1; 1652 } 1653 } else { 1654 if (lo === 0) { 1655 lo = this.UINT_MAX; 1656 hi -= 1; 1657 } else { 1658 lo -= 1; 1659 } 1660 } 1661 return doubleBits.pack(lo, hi); 1662 } 1663 }; 1664 1665 JXG.Math.IntervalArithmetic.PI = new MatInterval( 1666 Mat.IntervalArithmetic.piLow, 1667 Mat.IntervalArithmetic.piHigh 1668 ); 1669 JXG.Math.IntervalArithmetic.PI_HALF = new MatInterval( 1670 Mat.IntervalArithmetic.piHalfLow, 1671 Mat.IntervalArithmetic.piHalfHigh 1672 ); 1673 JXG.Math.IntervalArithmetic.PI_TWICE = new MatInterval( 1674 Mat.IntervalArithmetic.piTwiceLow, 1675 Mat.IntervalArithmetic.piTwiceHigh 1676 ); 1677 JXG.Math.IntervalArithmetic.ZERO = new MatInterval(0); 1678 JXG.Math.IntervalArithmetic.ONE = new MatInterval(1); 1679 JXG.Math.IntervalArithmetic.WHOLE = new MatInterval().setWhole(); 1680 JXG.Math.IntervalArithmetic.EMPTY = new MatInterval().setEmpty(); 1681 1682 export default JXG.Math.IntervalArithmetic; 1683