tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

tcuInterval.js (18617B)


      1 /*-------------------------------------------------------------------------
      2 * drawElements Quality Program Tester Core
      3 * ----------------------------------------
      4 *
      5 * Copyright 2014 The Android Open Source Project
      6 *
      7 * Licensed under the Apache License, Version 2.0 (the "License");
      8 * you may not use this file except in compliance with the License.
      9 * You may obtain a copy of the License at
     10 *
     11 *      http://www.apache.org/licenses/LICENSE-2.0
     12 *
     13 * Unless required by applicable law or agreed to in writing, software
     14 * distributed under the License is distributed on an "AS IS" BASIS,
     15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 * See the License for the specific language governing permissions and
     17 * limitations under the License.
     18 *
     19 *//*!
     20 * \file
     21 * \brief Interval arithmetic and floating point precisions.
     22 *//*--------------------------------------------------------------------*/
     23 'use strict';
     24 goog.provide('framework.common.tcuInterval');
     25 goog.require('framework.delibs.debase.deMath');
     26 
     27 goog.scope(function() {
     28 
     29     var tcuInterval = framework.common.tcuInterval;
     30     var deMath = framework.delibs.debase.deMath;
     31 
     32    /**
     33     * @typedef {function(number):number}
     34     */
     35    tcuInterval.DoubleFunc1;
     36 
     37    /**
     38     * @typedef {function(number, number):number}
     39     */
     40    tcuInterval.DoubleFunc2;
     41 
     42    /**
     43     * @typedef {function(number,number,number):number}
     44     */
     45    tcuInterval.DoubleFunc3;
     46 
     47    /**
     48     * @typedef {function(number):tcuInterval.Interval}
     49     */
     50    tcuInterval.DoubleIntervalFunc1;
     51 
     52    /**
     53     * @typedef {function(number,number):tcuInterval.Interval}
     54     */
     55    tcuInterval.DoubleIntervalFunc2;
     56 
     57    /**
     58     * @typedef {function(number,number,number):tcuInterval.Interval}
     59     */
     60    tcuInterval.DoubleIntervalFunc3;
     61 
     62    /**
     63     * @param {function(number): number} func
     64     * @param {tcuInterval.Interval} arg0
     65     * @return {tcuInterval.Interval}
     66     */
     67    tcuInterval.applyMonotone1p = function(func, arg0) {
     68        /**
     69         * @param {number=} x
     70         * @param {number=} y
     71         * @return {number}
     72         */
     73        var body = function(x, y) {
     74            x = x || 0;
     75            return func(x);
     76        };
     77        return tcuInterval.applyMonotone1(arg0,
     78            function(x) { return tcuInterval.setInterval(body, x); });
     79    };
     80 
     81    /**
     82     * @param {function(number): tcuInterval.Interval} func
     83     * @param {tcuInterval.Interval} arg0
     84     * @return {tcuInterval.Interval}
     85     */
     86    tcuInterval.applyMonotone1i = function(func, arg0) {
     87        return tcuInterval.withIntervals(func(arg0.lo()), func(arg0.hi()));
     88    };
     89 
     90    /**
     91     * @param {function(number, number): number} func
     92     * @param {tcuInterval.Interval} arg0
     93     * @param {tcuInterval.Interval} arg1
     94     * @return {tcuInterval.Interval}
     95     */
     96    tcuInterval.applyMonotone2p = function(func, arg0, arg1) {
     97        /**
     98         * @param {number=} x
     99         * @param {number=} y
    100         * @return {number}
    101         */
    102        var body = function(x, y) {
    103            x = x || 0;
    104            y = y || 0;
    105            return func(x, y);
    106        };
    107        return tcuInterval.applyMonotone2(arg0, arg1,
    108            function(x, y) { return tcuInterval.setInterval(body, x, y); });
    109    };
    110 
    111    /**
    112     * @param {function(number, number): tcuInterval.Interval} func
    113     * @param {tcuInterval.Interval} arg0
    114     * @param {tcuInterval.Interval} arg1
    115     * @return {tcuInterval.Interval}
    116     */
    117    tcuInterval.applyMonotone2i = function(func, arg0, arg1) {
    118        /** @type {number} */ var lo0 = arg0.lo();
    119        /** @type {number} */ var hi0 = arg0.hi();
    120        /** @type {number} */ var lo1 = arg1.lo();
    121        /** @type {number} */ var hi1 = arg1.hi();
    122        var a = tcuInterval.withIntervals(func(lo0, lo1), func(lo0, hi1));
    123        var b = tcuInterval.withIntervals(func(hi0, lo1), func(hi0, hi1));
    124        return tcuInterval.withIntervals(a, b);
    125    };
    126 
    127    /**
    128     * @constructor
    129     * @param {number=} val
    130     */
    131    tcuInterval.Interval = function(val) {
    132        if (val === undefined) {
    133            this.m_hasNaN = false;
    134            this.m_lo = Number.POSITIVE_INFINITY;
    135            this.m_hi = Number.NEGATIVE_INFINITY;
    136        } else {
    137            this.m_hasNaN = isNaN(val);
    138            this.m_lo = this.m_hasNaN ? Number.POSITIVE_INFINITY : val;
    139            this.m_hi = this.m_hasNaN ? Number.NEGATIVE_INFINITY : val;
    140        }
    141    };
    142 
    143    tcuInterval.Interval.prototype.toString = function() {
    144        var str = 'Interval(' + this.m_lo + ', ' + this.m_hi;
    145        if (this.m_hasNaN)
    146            str += ', hasNaN';
    147        str += ')';
    148        return str;
    149    };
    150 
    151    /**
    152     * @param {tcuInterval.Interval} a
    153     * @param {tcuInterval.Interval} b
    154     * @return {tcuInterval.Interval}
    155     */
    156    tcuInterval.withIntervals = function(a, b) {
    157        /** @type {tcuInterval.Interval} */ var interval = new tcuInterval.Interval();
    158        interval.m_hasNaN = (a.m_hasNaN || b.m_hasNaN);
    159        interval.m_lo = Math.min(a.m_lo, b.m_lo);
    160        interval.m_hi = Math.max(a.m_hi, b.m_hi);
    161        return interval;
    162    };
    163 
    164    /**
    165     * @param {number} a
    166     * @param {number} b
    167     * @return {tcuInterval.Interval}
    168     */
    169    tcuInterval.withNumbers = function(a, b) {
    170        var x = new tcuInterval.Interval(a);
    171        var y = new tcuInterval.Interval(b);
    172        return tcuInterval.withIntervals(x, y);
    173    };
    174 
    175    /**
    176     * @param {boolean} hasNaN_
    177     * @param {number} lo_
    178     * @param {number} hi_
    179     * @return {tcuInterval.Interval}
    180     */
    181    tcuInterval.withParams = function(hasNaN_, lo_, hi_) {
    182        /** @type {tcuInterval.Interval} */ var interval = new tcuInterval.Interval();
    183        interval.m_hasNaN = hasNaN_;
    184        interval.m_lo = lo_;
    185        interval.m_hi = hi_;
    186        return interval;
    187    };
    188 
    189    /**
    190     * @return {number}
    191     */
    192    tcuInterval.Interval.prototype.length = function() {
    193        return this.m_hi - this.m_lo;
    194    };
    195 
    196    /**
    197     * @return {number}
    198     */
    199    tcuInterval.Interval.prototype.lo = function() {
    200        return this.m_lo;
    201    };
    202 
    203    /**
    204     * @return {number}
    205     */
    206    tcuInterval.Interval.prototype.hi = function() {
    207        return this.m_hi;
    208    };
    209 
    210    /**
    211     * @return {boolean}
    212     */
    213    tcuInterval.Interval.prototype.hasNaN = function() {
    214        return this.m_hasNaN;
    215    };
    216 
    217    /**
    218     * @return {tcuInterval.Interval}
    219     */
    220    tcuInterval.Interval.prototype.nan = function() {
    221        return this.m_hasNaN ? new tcuInterval.Interval(NaN) : new tcuInterval.Interval();
    222    };
    223 
    224    /**
    225     * @return {boolean}
    226     */
    227    tcuInterval.Interval.prototype.empty = function() {
    228        return this.m_lo > this.m_hi;
    229    };
    230 
    231    /**
    232     * @return {boolean}
    233     */
    234    tcuInterval.Interval.prototype.isFinite = function() {
    235        return isFinite(this.m_lo) && isFinite(this.m_hi);
    236    };
    237 
    238    /**
    239     * @return {boolean}
    240     */
    241    tcuInterval.Interval.prototype.isOrdinary = function() {
    242        return !this.hasNaN() && !this.empty() && this.isFinite();
    243    };
    244 
    245    /**
    246     * @param {tcuInterval.Interval} other
    247     * @return {tcuInterval.Interval}
    248     */
    249    tcuInterval.Interval.prototype.operatorOrBinary = function(other) {
    250        /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
    251        temp.m_hasNaN = this.m_hasNaN || other.m_hasNaN;
    252        temp.m_lo = Math.min(this.m_lo, other.m_lo);
    253        temp.m_hi = Math.max(this.m_hi, other.m_hi);
    254        return temp;
    255    };
    256 
    257    /**
    258     * @param {tcuInterval.Interval} other
    259     */
    260    tcuInterval.Interval.prototype.operatorOrAssignBinary = function(other) {
    261        /** @type {tcuInterval.Interval} */ var temp = this.operatorOrBinary(other);
    262        this.m_hasNaN = temp.m_hasNaN;
    263        this.m_lo = temp.m_lo;
    264        this.m_hi = temp.m_hi;
    265    };
    266 
    267    /**
    268     * @param {tcuInterval.Interval} other
    269     * @return {tcuInterval.Interval}
    270     */
    271    tcuInterval.Interval.prototype.operatorAndBinary = function(other) {
    272        /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
    273        temp.m_hasNaN = this.m_hasNaN && other.m_hasNaN;
    274        temp.m_lo = Math.max(this.m_lo, other.m_lo);
    275        temp.m_hi = Math.min(this.m_hi, other.m_hi);
    276        return temp;
    277    };
    278 
    279    /**
    280     * @param {tcuInterval.Interval} other
    281     */
    282    tcuInterval.Interval.prototype.operatorAndAssignBinary = function(other) {
    283        /** @type {tcuInterval.Interval} */ var temp = this.operatorAndBinary(other);
    284        this.m_hasNaN = temp.m_hasNaN;
    285        this.m_lo = temp.m_lo;
    286        this.m_hi = temp.m_hi;
    287    };
    288 
    289    /**
    290     * @param {tcuInterval.Interval} other
    291     * @return {boolean}
    292     */
    293    tcuInterval.Interval.prototype.contains = function(other) {
    294        return (other.lo() >= this.lo() && other.hi() <= this.hi() &&
    295                (!other.hasNaN() || this.hasNaN()));
    296    };
    297 
    298    /**
    299     * @param {tcuInterval.Interval} other
    300     * @return {boolean}
    301     */
    302    tcuInterval.Interval.prototype.intersects = function(other) {
    303        return ((other.hi() >= this.lo() && other.lo() >= this.hi()) ||
    304                (other.hasNaN() && this.hasNaN()));
    305    };
    306 
    307    /**
    308     * @return {tcuInterval.Interval}
    309     */
    310    tcuInterval.Interval.prototype.operatorNegative = function() {
    311        /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
    312        temp.m_hasNaN = this.m_hasNaN;
    313        temp.m_lo = -this.m_hi;
    314        temp.m_hi = -this.m_lo;
    315        return temp;
    316    };
    317 
    318    /**
    319     * @param {boolean=} nan
    320     * @return {tcuInterval.Interval}
    321     */
    322    tcuInterval.unbounded = function(nan) {
    323        if (nan === undefined)
    324            nan = false;
    325        return tcuInterval.withParams(nan, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);
    326    };
    327 
    328    /**
    329     * @return {number}
    330     */
    331    tcuInterval.Interval.prototype.midpoint = function() {
    332        return 0.5 * (this.hi() + this.lo()); // returns NaN when not bounded
    333    };
    334 
    335    /**
    336     * @param {tcuInterval.Interval} other
    337     * @return {boolean}
    338     */
    339    tcuInterval.Interval.prototype.operatorCompare = function(other) {
    340        return ((this.m_hasNaN == other.m_hasNaN) &&
    341                ((this.empty() && other.empty()) ||
    342                 (this.m_lo == other.m_lo && this.m_hi == other.m_hi)));
    343    };
    344 
    345    /**
    346     * @param {tcuInterval.Interval} x
    347     * @return {tcuInterval.Interval}
    348     */
    349    tcuInterval.Interval.operatorPositive = function(x) {
    350        return x;
    351    };
    352 
    353    /**
    354     * @param {tcuInterval.Interval} x
    355     * @return {tcuInterval.Interval}
    356     */
    357    tcuInterval.Interval.exp2 = function(x) {
    358        // std::pow
    359        return tcuInterval.applyMonotone2p(Math.pow, new tcuInterval.Interval(2), x);
    360    };
    361 
    362    /**
    363     * @param {tcuInterval.Interval} x
    364     * @return {tcuInterval.Interval}
    365     */
    366    tcuInterval.Interval.exp = function(x) {
    367        // std::exp
    368        return tcuInterval.applyMonotone1p(Math.exp, x);
    369    };
    370 
    371    /**
    372     * @param {tcuInterval.Interval} x
    373     * @return {tcuInterval.Interval}
    374     */
    375    tcuInterval.Interval.sign = function(x) {
    376        // TODO
    377        throw new Error('Unimplemented');
    378    };
    379 
    380    /**
    381     * @param {tcuInterval.Interval} x
    382     * @param {tcuInterval.Interval} y
    383     * @return {tcuInterval.Interval}
    384     */
    385    tcuInterval.Interval.operatorSum = function(x, y) {
    386        /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
    387 
    388        if (!x.empty() && !y.empty())
    389            ret = tcuInterval.setIntervalBounds(function(dummy) {return x.lo() + y.lo();}, function(dummy) {return x.hi() + y.hi();});
    390        if (x.hasNaN() || y.hasNaN())
    391            ret.operatorOrAssignBinary(new tcuInterval.Interval(NaN));
    392 
    393        return ret;
    394    };
    395 
    396    /**
    397     * @param {tcuInterval.Interval} x
    398     * @param {tcuInterval.Interval} y
    399     * @return {tcuInterval.Interval}
    400     */
    401    tcuInterval.Interval.operatorSub = function(x, y) {
    402        /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
    403 
    404        /**
    405         * @param {number=} x
    406         * @param {number=} y
    407         * @return {tcuInterval.Interval}
    408         */
    409        var body = function(x, y) {
    410            return new tcuInterval.Interval(x - y);
    411        };
    412 
    413        ret = tcuInterval.applyMonotone2(x, y, body);
    414        return ret;
    415    };
    416 
    417    /**
    418     * @param {tcuInterval.Interval} x
    419     * @param {tcuInterval.Interval} y
    420     * @return {tcuInterval.Interval}
    421     */
    422    tcuInterval.Interval.operatorMul = function(x, y) {
    423        /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
    424 
    425        /**
    426         * @param {number=} x
    427         * @param {number=} y
    428         * @return {tcuInterval.Interval}
    429         */
    430        var body = function(x, y) {
    431            return new tcuInterval.Interval(x * y);
    432        };
    433 
    434        ret = tcuInterval.applyMonotone2(x, y, body);
    435 
    436        return ret;
    437    };
    438 
    439    /**
    440     * @param {tcuInterval.Interval} nom
    441     * @param {tcuInterval.Interval} den
    442     * @return {tcuInterval.Interval}
    443     */
    444    tcuInterval.Interval.operatorDiv = function(nom, den) {
    445        if (den.contains(new tcuInterval.Interval(0))) {
    446            // \todo [2014-03-21 lauri] Non-inf endpoint when one den endpoint is
    447            // zero and nom doesn't cross zero?
    448            return tcuInterval.unbounded();
    449        } else {
    450            /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
    451            /**
    452             * @param {number=} x
    453             * @param {number=} y
    454             * @return {tcuInterval.Interval}
    455             */
    456            var body = function(x, y) {
    457                return new tcuInterval.Interval(x / y);
    458            };
    459 
    460            ret = tcuInterval.applyMonotone2(nom, den, body);
    461 
    462            return ret;
    463        }
    464    };
    465 
    466    /**
    467     * @param {tcuInterval.Interval} x
    468     * @return {tcuInterval.Interval}
    469     */
    470    tcuInterval.Interval.prototype.abs = function(x) {
    471        //std::abs
    472        /** @type {tcuInterval.Interval} */ var mono = tcuInterval.applyMonotone1p(Math.abs, x);
    473        var zero = new tcuInterval.Interval(0);
    474        if (x.contains(zero))
    475            return tcuInterval.withIntervals(zero, mono);
    476 
    477        return mono;
    478    };
    479 
    480    /**
    481     * @param {tcuInterval.Interval} x
    482     * @return {tcuInterval.Interval}
    483     */
    484    tcuInterval.Interval.sqrt = function(x) {
    485        return tcuInterval.applyMonotone1p(Math.sqrt, x);
    486    };
    487 
    488    /**
    489     * @param {tcuInterval.Interval} x
    490     * @return {tcuInterval.Interval}
    491     */
    492    tcuInterval.Interval.inverseSqrt = function(x) {
    493        var ret = new tcuInterval.Interval(1);
    494        ret = tcuInterval.Interval.operatorDiv(ret, tcuInterval.Interval.sqrt(x));
    495        return ret;
    496    };
    497 
    498 /**
    499 * @param {function(number=, number=): number} setLow
    500 * @param {function(number=, number=): number} setHigh
    501 * @param {number=} arg0
    502 * @param {number=} arg1
    503 * @return {tcuInterval.Interval}
    504 */
    505 tcuInterval.setIntervalBounds = function(setLow, setHigh, arg0, arg1) {
    506    // TODO: No support for rounding modes. Originally, setLow() was rounded down and setHigh() rounded up
    507    var lo = new tcuInterval.Interval(setLow(arg0, arg1));
    508    var hi = new tcuInterval.Interval(setHigh(arg0, arg1));
    509    return lo.operatorOrBinary(hi);
    510 };
    511 
    512 /**
    513 * @param {function(number=, number=): number} set
    514 * @param {number=} arg0
    515 * @param {number=} arg1
    516 * @return {tcuInterval.Interval}
    517 */
    518 tcuInterval.setInterval = function(set, arg0, arg1) {
    519    return tcuInterval.setIntervalBounds(set, set, arg0, arg1);
    520 };
    521 
    522 /**
    523 * @param {tcuInterval.Interval} arg
    524 * @param {function(number): tcuInterval.Interval} body
    525 * @return {tcuInterval.Interval}
    526 */
    527 tcuInterval.applyMonotone1 = function(arg, body) {
    528    var ret = new tcuInterval.Interval();
    529 
    530    if (!arg.empty()) {
    531        var lo = body(arg.lo());
    532        var hi = body(arg.hi());
    533        ret = lo.operatorOrBinary(hi);
    534    }
    535 
    536    if (arg.hasNaN()) {
    537        ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
    538    }
    539 
    540    return ret;
    541 };
    542 
    543 /**
    544 * TODO: Check if this function works properly
    545 * @param {tcuInterval.Interval} arg0
    546 * @param {tcuInterval.Interval} arg1
    547 * @param {function(number, number): tcuInterval.Interval} body
    548 * @return {tcuInterval.Interval}
    549 */
    550 tcuInterval.applyMonotone2 = function(arg0, arg1, body) {
    551    var ret = new tcuInterval.Interval();
    552 
    553    if (!arg0.empty() && !arg1.empty()) {
    554        var lo0 = body(arg0.lo(), arg1.lo());
    555        var lo1 = body(arg0.lo(), arg1.hi());
    556        var hi0 = body(arg0.hi(), arg1.lo());
    557        var hi1 = body(arg0.hi(), arg1.hi());
    558        var a = lo0.operatorOrBinary(hi0);
    559        var b = lo1.operatorOrBinary(hi1);
    560        ret = a.operatorOrBinary(b);
    561    }
    562 
    563    if (arg0.hasNaN() || arg1.hasNaN()) {
    564        ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
    565    }
    566 
    567    return ret;
    568 };
    569 
    570 /**
    571 * TODO: Check if this function works properly
    572 * @param {tcuInterval.Interval} arg0
    573 * @param {tcuInterval.Interval} arg1
    574 * @param {tcuInterval.Interval} arg2
    575 * @param {function(number, number, number): tcuInterval.Interval} body
    576 * @return {tcuInterval.Interval}
    577 */
    578 tcuInterval.applyMonotone3 = function(arg0, arg1, arg2, body) {
    579    var ret = new tcuInterval.Interval();
    580 
    581    if (!arg0.empty() && !arg1.empty() && !arg2.empty()) {
    582        var i0 = body(arg0.lo(), arg1.lo(), arg2.lo());
    583        var i1 = body(arg0.lo(), arg1.lo(), arg2.hi());
    584        var i2 = body(arg0.lo(), arg1.hi(), arg2.lo());
    585        var i3 = body(arg0.lo(), arg1.hi(), arg2.hi());
    586        var i4 = body(arg0.hi(), arg1.lo(), arg2.lo());
    587        var i5 = body(arg0.hi(), arg1.lo(), arg2.hi());
    588        var i6 = body(arg0.hi(), arg1.hi(), arg2.lo());
    589        var i7 = body(arg0.hi(), arg1.hi(), arg2.hi());
    590 
    591        var low = Math.min(i0.lo(), i1.lo(), i2.lo(), i3.lo(), i4.lo(), i5.lo(), i6.lo(), i7.lo());
    592        var high = Math.max(i0.hi(), i1.hi(), i2.hi(), i3.hi(), i4.hi(), i5.hi(), i6.hi(), i7.hi());
    593        var hasNaN = i0.hasNaN() || i1.hasNaN() || i2.hasNaN() || i3.hasNaN() || i4.hasNaN() || i5.hasNaN() || i6.hasNaN() || i7.hasNaN();
    594 
    595        ret = tcuInterval.withParams(hasNaN, low, high);
    596    }
    597 
    598    if (arg0.hasNaN() || arg1.hasNaN() || arg2.hasNaN()) {
    599        ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
    600    }
    601 
    602    return ret;
    603 };
    604 
    605 /** @const */ tcuInterval.POSITIVE_INFINITY = new tcuInterval.Interval(Infinity);
    606 /** @const */ tcuInterval.NEGATIVE_INFINITY = new tcuInterval.Interval(-Infinity);
    607 /** @const */ tcuInterval.ZERO = new tcuInterval.Interval(0);
    608 /** @const */ tcuInterval.NAN = new tcuInterval.Interval(NaN);
    609 });