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