diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js new file mode 100644 index 0000000000..a0b4dc82cf --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js @@ -0,0 +1,349 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program Tester Core + * ---------------------------------------- + * + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *//*! + * \file + * \brief Adjustable-precision floating point operations. + *//*--------------------------------------------------------------------*/ + 'use strict'; + goog.provide('framework.common.tcuFloatFormat'); + + goog.require('framework.common.tcuInterval'); +goog.require('framework.delibs.debase.deMath'); + + goog.scope(function() { + + var tcuFloatFormat = framework.common.tcuFloatFormat; + var deMath = framework.delibs.debase.deMath; + var tcuInterval = framework.common.tcuInterval; + + /** + * @param {tcuFloatFormat.YesNoMaybe} choice + * @param {tcuInterval.Interval} no + * @param {tcuInterval.Interval} yes + * @return {tcuInterval.Interval} + */ + tcuFloatFormat.chooseInterval = function(choice, no, yes) { + switch (choice) { + case tcuFloatFormat.YesNoMaybe.NO: return no; + case tcuFloatFormat.YesNoMaybe.YES: return yes; + case tcuFloatFormat.YesNoMaybe.MAYBE: return no.operatorOrBinary(yes); + default: throw new Error('Impossible case'); + } + }; + + /** + * @param {number} maxExp + * @param {number} fractionBits + * @return {number} + */ + tcuFloatFormat.computeMaxValue = function(maxExp, fractionBits) { + return deMath.deLdExp(1, maxExp) + deMath.deLdExp(Math.pow(2, fractionBits) - 1, maxExp - fractionBits); + }; + + /** + * @enum {number} + */ + tcuFloatFormat.YesNoMaybe = { + NO: 0, + MAYBE: 1, + YES: 2 + }; + + /** + * @constructor + * @param {number} minExp + * @param {number} maxExp + * @param {number} fractionBits + * @param {boolean} exactPrecision + * @param {tcuFloatFormat.YesNoMaybe=} hasSubnormal + * @param {tcuFloatFormat.YesNoMaybe=} hasInf + * @param {tcuFloatFormat.YesNoMaybe=} hasNaN + */ + tcuFloatFormat.FloatFormat = function(minExp, maxExp, fractionBits, exactPrecision, hasSubnormal, hasInf, hasNaN) { + // /** @type{number} */ var exponentShift (int exp) const; + // Interval clampValue (double d) const; + + /** @type {number} */ this.m_minExp = minExp; // Minimum exponent, inclusive + /** @type {number} */ this.m_maxExp = maxExp; // Maximum exponent, inclusive + /** @type {number} */ this.m_fractionBits = fractionBits; // Number of fractional bits in significand + /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasSubnormal = hasSubnormal === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasSubnormal; // Does the format support denormalized numbers? + /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasInf = hasInf === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasInf; // Does the format support infinities? + /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasNaN = hasNaN === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasNaN; // Does the format support NaNs? + /** @type {boolean} */ this.m_exactPrecision = exactPrecision; // Are larger precisions disallowed? + /** @type {number} */ this.m_maxValue = tcuFloatFormat.computeMaxValue(maxExp, fractionBits); + }; + + /** + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.getMinExp = function() { + return this.m_minExp; + }; + + /** + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.getMaxExp = function() { + return this.m_maxExp; + }; + + /** + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.getMaxValue = function() { + return this.m_maxValue; + }; + + /** + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.getFractionBits = function() { + return this.m_fractionBits; + }; + + /** + * @return {tcuFloatFormat.YesNoMaybe} + */ + tcuFloatFormat.FloatFormat.prototype.hasSubnormal = function() { + return this.m_hasSubnormal; + }; + + /** + * @return {tcuFloatFormat.YesNoMaybe} + */ + tcuFloatFormat.FloatFormat.prototype.hasInf = function() { + return this.m_hasInf; + }; + + /** + * @param {number} x + * @param {number} count + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.ulp = function(x, count) { + var breakdown = deMath.deFractExp(Math.abs(x)); + /** @type {number} */ var exp = breakdown.exponent; + /** @type {number} */ var frac = breakdown.significand; + + if (isNaN(frac)) + return NaN; + else if (!isFinite(frac)) + return deMath.deLdExp(1.0, this.m_maxExp - this.m_fractionBits); + else if (frac == 1.0) { + // Harrison's ULP: choose distance to closest (i.e. next lower) at binade + // boundary. + --exp; + } else if (frac == 0.0) + exp = this.m_minExp; + + // ULP cannot be lower than the smallest quantum. + exp = Math.max(exp, this.m_minExp); + + /** @type {number} */ var oneULP = deMath.deLdExp(1.0, exp - this.m_fractionBits); + // ScopedRoundingMode ctx (DE_ROUNDINGMODE_TO_POSITIVE_INF); + + return oneULP * count; + }; + + /** + * Return the difference between the given nominal exponent and + * the exponent of the lowest significand bit of the + * representation of a number with this format. + * For normal numbers this is the number of significand bits, but + * for subnormals it is less and for values of exp where 2^exp is too + * small to represent it is <0 + * @param {number} exp + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.exponentShift = function(exp) { + return this.m_fractionBits - Math.max(this.m_minExp - exp, 0); + }; + + /** + * @param {number} d + * @param {boolean} upward + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.round = function(d, upward) { + var breakdown = deMath.deFractExp(d); + /** @type {number} */ var exp = breakdown.exponent; + /** @type {number} */ var frac = breakdown.significand; + + var shift = this.exponentShift(exp); + var shiftFrac = deMath.deLdExp(frac, shift); + var roundFrac = upward ? Math.ceil(shiftFrac) : Math.floor(shiftFrac); + + return deMath.deLdExp(roundFrac, exp - shift); + }; + + /** + * Return the range of numbers that `d` might be converted to in the + * floatformat, given its limitations with infinities, subnormals and maximum + * exponent. + * @param {number} d + * @return {tcuInterval.Interval} + */ + tcuFloatFormat.FloatFormat.prototype.clampValue = function(d) { + /** @type {number} */ var rSign = deMath.deSign(d); + /** @type {number} */ var rExp = 0; + + // DE_ASSERT(!isNaN(d)); + + var breakdown = deMath.deFractExp(d); + rExp = breakdown.exponent; + if (rExp < this.m_minExp) + return tcuFloatFormat.chooseInterval(this.m_hasSubnormal, new tcuInterval.Interval(rSign * 0.0), new tcuInterval.Interval(d)); + else if (!isFinite(d) || rExp > this.m_maxExp) + return tcuFloatFormat.chooseInterval(this.m_hasInf, new tcuInterval.Interval(rSign * this.getMaxValue()), new tcuInterval.Interval(rSign * Number.POSITIVE_INFINITY)); + + return new tcuInterval.Interval(d); + }; + + /** + * @param {number} d + * @param {boolean} upward + * @param {boolean} roundUnderOverflow + * @return {number} + */ + tcuFloatFormat.FloatFormat.prototype.roundOutDir = function(d, upward, roundUnderOverflow) { + var breakdown = deMath.deFractExp(d); + var exp = breakdown.exponent; + + if (roundUnderOverflow && exp > this.m_maxExp && (upward == (d < 0.0))) + return deMath.deSign(d) * this.getMaxValue(); + else + return this.round(d, upward); + }; + + /** + * @param {tcuInterval.Interval} x + * @param {boolean} roundUnderOverflow + * @return {tcuInterval.Interval} + */ + tcuFloatFormat.FloatFormat.prototype.roundOut = function(x, roundUnderOverflow) { + /** @type {tcuInterval.Interval} */ var ret = x.nan(); + + if (!x.empty()) { + var a = new tcuInterval.Interval(this.roundOutDir(x.lo(), false, roundUnderOverflow)); + var b = new tcuInterval.Interval(this.roundOutDir(x.hi(), true, roundUnderOverflow)); + ret.operatorOrAssignBinary(tcuInterval.withIntervals(a, b)); + } + return ret; + }; + + //! Return the range of numbers that might be used with this format to + //! represent a number within `x`. + /** + * @param {tcuInterval.Interval} x + * @return {tcuInterval.Interval} + */ + tcuFloatFormat.FloatFormat.prototype.convert = function(x) { + /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval(); + /** @type {tcuInterval.Interval} */ var tmp = x; + + if (x.hasNaN()) { + // If NaN might be supported, NaN is a legal return value + if (this.m_hasNaN != tcuFloatFormat.YesNoMaybe.NO) + ret.operatorOrAssignBinary(new tcuInterval.Interval(NaN)); + + // If NaN might not be supported, any (non-NaN) value is legal, + // _subject_ to clamping. Hence we modify tmp, not ret. + if (this.m_hasNaN != tcuFloatFormat.YesNoMaybe.YES) + tmp = tcuInterval.unbounded(); + } + + // Round both bounds _inwards_ to closest representable values. + if (!tmp.empty()) + ret.operatorOrAssignBinary( + this.clampValue(this.round(tmp.lo(), true)).operatorOrBinary( + this.clampValue(this.round(tmp.hi(), false)))); + + // If this format's precision is not exact, the (possibly out-of-bounds) + // original value is also a possible result. + if (!this.m_exactPrecision) + ret.operatorOrAssignBinary(x); + + return ret; + }; + + /** + * @param {number} x + * @return {string} + */ + tcuFloatFormat.FloatFormat.prototype.floatToHex = function(x) { + if (isNaN(x)) + return 'NaN'; + else if (!isFinite(x)) + return (x < 0.0 ? '-' : '+') + ('inf'); + else if (x == 0.0) // \todo [2014-03-27 lauri] Negative zero + return '0.0'; + + return x.toString(10); + // TODO + // var breakdown = deMath.deFractExp(deAbs(x)); + // /** @type{number} */ var exp = breakdown.exponent; + // /** @type{number} */ var frac = breakdown.significand; + // /** @type{number} */ var shift = this.exponentShift(exp); + // /** @type{number} */ var bits = deUint64(deLdExp(frac, shift)); + // /** @type{number} */ var whole = bits >> m_fractionBits; + // /** @type{number} */ var fraction = bits & ((deUint64(1) << m_fractionBits) - 1); + // /** @type{number} */ var exponent = exp + m_fractionBits - shift; + // /** @type{number} */ var numDigits = (this.m_fractionBits + 3) / 4; + // /** @type{number} */ var aligned = fraction << (numDigits * 4 - m_fractionBits); + // /** @type{string} */ var oss = ''; + + // oss + (x < 0 ? '-' : '') + // + '0x' + whole + '.' + // + std::hex + std::setw(numDigits) + std::setfill('0') + aligned + // + 'p' + std::dec + std::setw(0) + exponent; + //return oss; + }; + + /** + * @param {tcuInterval.Interval} interval + * @return {string} + */ + tcuFloatFormat.FloatFormat.prototype.intervalToHex = function(interval) { + if (interval.empty()) + return interval.hasNaN() ? '{ NaN }' : '{}'; + + else if (interval.lo() == interval.hi()) + return ((interval.hasNaN() ? '{ NaN, ' : '{ ') + + this.floatToHex(interval.lo()) + ' }'); + else if (interval == tcuInterval.unbounded(true)) + return '<any>'; + + return ((interval.hasNaN() ? '{ NaN } | ' : '') + + '[' + this.floatToHex(interval.lo()) + ', ' + this.floatToHex(interval.hi()) + ']'); + }; + + /** + * @return {tcuFloatFormat.FloatFormat} + */ + tcuFloatFormat.nativeDouble = function() { + return new tcuFloatFormat.FloatFormat(-1021 - 1, // min_exponent + 1024 - 1, // max_exponent + 53 - 1, // digits + true, // has_denorm + tcuFloatFormat.YesNoMaybe.YES, // has_infinity + tcuFloatFormat.YesNoMaybe.YES, // has_quiet_nan + tcuFloatFormat.YesNoMaybe.YES); // has_denorm + }; + +}); |