diff options
Diffstat (limited to '')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js | 862 |
1 files changed, 862 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js new file mode 100644 index 0000000000..0cc74fe5a9 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js @@ -0,0 +1,862 @@ +/*------------------------------------------------------------------------- + * drawElements Quality Program OpenGL ES Utilities + * ------------------------------------------------ + * + * 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. + * + */ + +'use strict'; +goog.provide('framework.common.tcuFloat'); +goog.require('framework.delibs.debase.deMath'); + +goog.scope(function() { + +var tcuFloat = framework.common.tcuFloat; +var deMath = framework.delibs.debase.deMath; + +var DE_ASSERT = function(x) { + if (!x) + throw new Error('Assert failed'); +}; + +tcuFloat.FloatFlags = { + FLOAT_HAS_SIGN: (1 << 0), + FLOAT_SUPPORT_DENORM: (1 << 1) +}; + +/** + * Defines a tcuFloat.FloatDescription object, which is an essential part of the tcuFloat.deFloat type. + * Holds the information that shapes the tcuFloat.deFloat. + * @constructor + */ +tcuFloat.FloatDescription = function(exponentBits, mantissaBits, exponentBias, flags) { + this.ExponentBits = exponentBits; + this.MantissaBits = mantissaBits; + this.ExponentBias = exponentBias; + this.Flags = flags; + + this.totalBitSize = 1 + this.ExponentBits + this.MantissaBits; + this.totalByteSize = Math.floor(this.totalBitSize / 8) + ((this.totalBitSize % 8) > 0 ? 1 : 0); +}; + +/** + * Builds a zero float of the current binary description. + * @param {number} sign + * @return {tcuFloat.deFloat} + */ +tcuFloat.FloatDescription.prototype.zero = function(sign) { + return tcuFloat.newDeFloatFromParameters(this.zeroNumber(sign), this); +}; + +tcuFloat.FloatDescription.prototype.zeroNumber = function(sign) { + return deMath.shiftLeft((sign > 0 ? 0 : 1), (this.ExponentBits + this.MantissaBits)); +}; + +/** + * Builds an infinity float representation of the current binary description. + * @param {number} sign + * @return {tcuFloat.deFloat} + */ +tcuFloat.FloatDescription.prototype.inf = function(sign) { + return tcuFloat.newDeFloatFromParameters(this.infNumber(sign), this); +}; + +tcuFloat.FloatDescription.prototype.infNumber = function(sign) { + return ((sign > 0 ? 0 : 1) << (this.ExponentBits + this.MantissaBits)) | + deMath.shiftLeft(((1 << this.ExponentBits) - 1), this.MantissaBits); //Unless using very large exponent types, native shift is safe here, i guess. +}; + +/** + * Builds a NaN float representation of the current binary description. + * @return {tcuFloat.deFloat} + */ +tcuFloat.FloatDescription.prototype.nan = function() { + return tcuFloat.newDeFloatFromParameters(this.nanNumber(), this); +}; + +tcuFloat.FloatDescription.prototype.nanNumber = function() { + return deMath.shiftLeft(1, (this.ExponentBits + this.MantissaBits)) - 1; +}; + +/** + * Builds a tcuFloat.deFloat number based on the description and the given + * sign, exponent and mantissa values. + * @param {number} sign + * @param {number} exponent + * @param {number} mantissa + * @return {tcuFloat.deFloat} + */ +tcuFloat.FloatDescription.prototype.construct = function(sign, exponent, mantissa) { + // Repurpose this otherwise invalid input as a shorthand notation for zero (no need for caller to care about internal representation) + /** @type {boolean} */ var isShorthandZero = exponent == 0 && mantissa == 0; + + // Handles the typical notation for zero (min exponent, mantissa 0). Note that the exponent usually used exponent (-ExponentBias) for zero/subnormals is not used. + // Instead zero/subnormals have the (normally implicit) leading mantissa bit set to zero. + + /** @type {boolean} */ var isDenormOrZero = (exponent == 1 - this.ExponentBias) && (deMath.shiftRight(mantissa, this.MantissaBits) == 0); + /** @type {number} */ var s = deMath.shiftLeft((sign < 0 ? 1 : 0), (this.ExponentBits + this.MantissaBits)); + /** @type {number} */ var exp = (isShorthandZero || isDenormOrZero) ? 0 : exponent + this.ExponentBias; + + DE_ASSERT(sign == +1 || sign == -1); + DE_ASSERT(isShorthandZero || isDenormOrZero || deMath.shiftRight(mantissa, this.MantissaBits) == 1); + DE_ASSERT((exp >> this.ExponentBits) == 0); //Native shift is safe + + return tcuFloat.newDeFloatFromParameters( + deMath.binaryOp( + deMath.binaryOp( + s, + deMath.shiftLeft(exp, this.MantissaBits), + deMath.BinaryOp.OR + ), + deMath.binaryOp( + mantissa, + deMath.shiftLeft(1, this.MantissaBits) - 1, + deMath.BinaryOp.AND + ), + deMath.BinaryOp.OR + ), + this + ); +}; + +/** + * Builds a tcuFloat.deFloat number based on the description and the given + * sign, exponent and binary mantissa values. + * @param {number} sign + * @param {number} exponent + * @param {number} mantissaBits The raw binary representation. + * @return {tcuFloat.deFloat} + */ +tcuFloat.FloatDescription.prototype.constructBits = function(sign, exponent, mantissaBits) { + /** @type {number} */ var signBit = sign < 0 ? 1 : 0; + /** @type {number} */ var exponentBits = exponent + this.ExponentBias; + + DE_ASSERT(sign == +1 || sign == -1); + DE_ASSERT((exponentBits >> this.ExponentBits) == 0); + DE_ASSERT(deMath.shiftRight(mantissaBits, this.MantissaBits) == 0); + + return tcuFloat.newDeFloatFromParameters( + deMath.binaryOp( + deMath.binaryOp( + deMath.shiftLeft( + signBit, + this.ExponentBits + this.MantissaBits + ), + deMath.shiftLeft(exponentBits, this.MantissaBits), + deMath.BinaryOp.OR + ), + mantissaBits, + deMath.BinaryOp.OR + ), + this + ); +}; + +/** + * Converts a tcuFloat.deFloat from it's own format description into the format described + * by this description. + * @param {tcuFloat.deFloat} other Other float to convert to this format description. + * @return {tcuFloat.deFloat} converted tcuFloat.deFloat + */ +tcuFloat.FloatDescription.prototype.convert = function(other) { + /** @type {number} */ var otherExponentBits = other.description.ExponentBits; + /** @type {number} */ var otherMantissaBits = other.description.MantissaBits; + /** @type {number} */ var otherExponentBias = other.description.ExponentBias; + /** @type {number} */ var otherFlags = other.description.Flags; + + /** @type {number} */ var bitDiff; + /** @type {number} */ var half; + /** @type {number} */ var bias; + + if (!(this.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && other.sign() < 0) { + // Negative number, truncate to zero. + return this.zero(+1); + } else if (other.isInf()) { + return this.inf(other.sign()); + } else if (other.isNaN()) { + return this.nan(); + } else if (other.isZero()) { + return this.zero(other.sign()); + } else { + /** @type {number} */ var eMin = 1 - this.ExponentBias; + /** @type {number} */ var eMax = ((1 << this.ExponentBits) - 2) - this.ExponentBias; + + /** @type {number} */ var s = deMath.shiftLeft(other.signBit(), (this.ExponentBits + this.MantissaBits)); // \note Not sign, but sign bit. + /** @type {number} */ var e = other.exponent(); + /** @type {number} */ var m = other.mantissa(); + + // Normalize denormalized values prior to conversion. + while (!deMath.binaryOp(m, deMath.shiftLeft(1, otherMantissaBits), deMath.BinaryOp.AND)) { + m = deMath.shiftLeft(m, 1); + e -= 1; + } + + if (e < eMin) { + // Underflow. + if ((this.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= this.MantissaBits)) { + // Shift and round (RTE). + bitDiff = (otherMantissaBits - this.MantissaBits) + (eMin - e); + half = deMath.shiftLeft(1, (bitDiff - 1)) - 1; + bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND); + + return tcuFloat.newDeFloatFromParameters( + deMath.binaryOp( + s, + deMath.shiftRight( + m + half + bias, + bitDiff + ), + deMath.BinaryOp.OR + ), + this + ); + } else + return this.zero(other.sign()); + } else { + // Remove leading 1. + m = deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, otherMantissaBits)), deMath.BinaryOp.AND); + + if (this.MantissaBits < otherMantissaBits) { + // Round mantissa (round to nearest even). + bitDiff = otherMantissaBits - this.MantissaBits; + half = deMath.shiftLeft(1, (bitDiff - 1)) - 1; + bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND); + + m = deMath.shiftRight(m + half + bias, bitDiff); + + if (deMath.binaryOp(m, deMath.shiftLeft(1, this.MantissaBits), deMath.BinaryOp.AND)) { + // Overflow in mantissa. + m = 0; + e += 1; + } + } else { + bitDiff = this.MantissaBits - otherMantissaBits; + m = deMath.shiftLeft(m, bitDiff); + } + + if (e > eMax) { + // Overflow. + return this.inf(other.sign()); + } else { + DE_ASSERT(deMath.deInRange32(e, eMin, eMax)); + DE_ASSERT(deMath.binaryOp((e + this.ExponentBias), deMath.binaryNot(deMath.shiftLeft(1, this.ExponentBits) - 1), deMath.BinaryOp.AND) == 0); + DE_ASSERT(deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, this.MantissaBits) - 1), deMath.BinaryOp.AND) == 0); + + return tcuFloat.newDeFloatFromParameters( + deMath.binaryOp( + deMath.binaryOp( + s, + deMath.shiftLeft( + e + this.ExponentBias, + this.MantissaBits + ), + deMath.BinaryOp.OR + ), + m, + deMath.BinaryOp.OR + ), + this + ); + } + } + } +}; + +/** + * tcuFloat.deFloat class - Empty constructor, builds a 32 bit float by default + * @constructor + */ +tcuFloat.deFloat = function() { + this.description = tcuFloat.description32; + + this.m_buffer = null; + this.m_array = null; + this.m_array32 = null; + this.bitValue = undefined; + this.signValue = undefined; + this.expValue = undefined; + this.mantissaValue = undefined; + + this.m_value = 0; +}; + +/** + * buffer - Get the deFloat's existing ArrayBuffer or create one if none exists. + * @return {ArrayBuffer} + */ +tcuFloat.deFloat.prototype.buffer = function() { + if (!this.m_buffer) + this.m_buffer = new ArrayBuffer(this.description.totalByteSize); + return this.m_buffer; +}; + +/** + * array - Get the deFloat's existing Uint8Array or create one if none exists. + * @return {Uint8Array} + */ +tcuFloat.deFloat.prototype.array = function() { + if (!this.m_array) + this.m_array = new Uint8Array(this.buffer()); + return this.m_array; +}; + +/** + * array32 - Get the deFloat's existing Uint32Array or create one if none exists. + * @return {Uint32Array} + */ +tcuFloat.deFloat.prototype.array32 = function() { + if (!this.m_array32) + this.m_array32 = new Uint32Array(this.buffer()); + return this.m_array32; +}; + +/** + * deFloatNumber - To be used immediately after constructor + * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number. + * @param {number} jsnumber + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.deFloatNumber = function(jsnumber) { + var view32 = new DataView(this.buffer()); + view32.setFloat32(0, jsnumber, true); //little-endian + this.m_value = view32.getFloat32(0, true); //little-endian + + // Clear cached values + this.bitValue = undefined; + this.signValue = undefined; + this.expValue = undefined; + this.mantissaValue = undefined; + + return this; +}; + +/** + * deFloatNumber64 - To be used immediately after constructor + * Builds a 64-bit tcuFloat.deFloat based on a 64-bit JS number. + * @param {number} jsnumber + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.deFloatNumber64 = function(jsnumber) { + var view64 = new DataView(this.buffer()); + view64.setFloat64(0, jsnumber, true); //little-endian + this.m_value = view64.getFloat64(0, true); //little-endian + + // Clear cached values + this.bitValue = undefined; + this.signValue = undefined; + this.expValue = undefined; + this.mantissaValue = undefined; + + return this; +}; + +/** + * Convenience function to build a 32-bit tcuFloat.deFloat based on a 64-bit JS number + * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number. + * @param {number} jsnumber + * @return {tcuFloat.deFloat} + */ +tcuFloat.newDeFloatFromNumber = function(jsnumber) { + return new tcuFloat.deFloat().deFloatNumber(jsnumber); +}; + +/** + * deFloatBuffer - To be used immediately after constructor + * Builds a tcuFloat.deFloat based on a buffer and a format description. + * The buffer is assumed to contain data of the given description. + * @param {ArrayBuffer} buffer + * @param {tcuFloat.FloatDescription} description + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.deFloatBuffer = function(buffer, description) { + this.m_buffer = buffer; + this.m_array = new Uint8Array(this.m_buffer); + this.m_array32 = new Uint32Array(this.m_buffer); + + this.m_value = deMath.arrayToNumber(this.m_array); + + // Clear cached values + this.bitValue = undefined; + this.signValue = undefined; + this.expValue = undefined; + this.mantissaValue = undefined; + + return this; +}; + +/** + * Convenience function to build a tcuFloat.deFloat based on a buffer and a format description + * The buffer is assumed to contain data of the given description. + * @param {ArrayBuffer} buffer + * @param {tcuFloat.FloatDescription} description + * @return {tcuFloat.deFloat} + */ +tcuFloat.newDeFloatFromBuffer = function(buffer, description) { + return new tcuFloat.deFloat().deFloatBuffer(buffer, description); +}; + +/** + * Set the tcuFloat.deFloat from the given bitwise representation. + * + * @param {number} jsnumber This is taken to be the bitwise representation of + * the floating point number represented by this deFloat. It must be an + * integer, less than 2^52, and compatible with the existing description. + * @return {tcuFloat.deFloat} + **/ +tcuFloat.deFloat.prototype.deFloatParametersNumber = function(jsnumber) { + /** @type {number} */ var jsnumberMax = -1 >>> (32 - this.description.totalBitSize); + DE_ASSERT(Number.isInteger(jsnumber) && jsnumber <= jsnumberMax); + + this.m_value = jsnumber; + deMath.numberToArray(this.m_array, jsnumber); + + // Clear cached values + this.bitValue = undefined; + this.signValue = undefined; + this.expValue = undefined; + this.mantissaValue = undefined; + + return this; +}; + +/** + * Initializes a tcuFloat.deFloat from the given bitwise representation, + * with the specified format description. + * + * @param {number} jsnumber This is taken to be the bitwise representation of + * the floating point number represented by this deFloat. It must be an + * integer, less than 2^52, and compatible with the new description. + * @param {tcuFloat.FloatDescription} description + * @return {tcuFloat.deFloat} + **/ +tcuFloat.deFloat.prototype.deFloatParameters = function(jsnumber, description) { + /** @type {number} */ var maxUint52 = 0x10000000000000; + DE_ASSERT(Number.isInteger(jsnumber) && jsnumber < maxUint52); + if (description.totalBitSize > 52) { + // The jsnumber representation for this number can't possibly be valid. + // Make sure it has a sentinel 0 value. + DE_ASSERT(jsnumber === 0); + } + + this.description = description; + + this.m_buffer = new ArrayBuffer(this.description.totalByteSize); + this.m_array = new Uint8Array(this.m_buffer); + + return this.deFloatParametersNumber(jsnumber); +}; + +/** + * Convenience function. Creates a tcuFloat.deFloat, then initializes it from + * the given bitwise representation, with the specified format description. + * + * @param {number} jsnumber This is taken to be the bitwise representation of + * the floating point number represented by this deFloat. It must be an + * integer, less than 2^52, and compatible with the new description. + * @param {tcuFloat.FloatDescription} description + * @return {tcuFloat.deFloat} + **/ +tcuFloat.newDeFloatFromParameters = function(jsnumber, description) { + return new tcuFloat.deFloat().deFloatParameters(jsnumber, description); +}; + +/** + * Returns bit range [begin, end) + * @param {number} begin + * @param {number} end + * @return {number} + */ +tcuFloat.deFloat.prototype.getBitRange = function(begin, end) { + if (this.description.totalBitSize <= 52) { + // this.bits() is invalid for more than 52 bits. + return deMath.getBitRange(this.bits(), begin, end); + } else { + return deMath.getArray32BitRange(this.array32(), begin, end); + } +}; + +/** + * Returns the raw binary representation value of the tcuFloat.deFloat + * @return {number} + */ +tcuFloat.deFloat.prototype.bits = function() { + if (typeof this.bitValue === 'undefined') + this.bitValue = deMath.arrayToNumber(this.array()); + return this.bitValue; +}; + +/** + * Returns the raw binary sign bit + * @return {number} + */ +tcuFloat.deFloat.prototype.signBit = function() { + if (typeof this.signValue === 'undefined') + this.signValue = this.getBitRange(this.description.totalBitSize - 1, this.description.totalBitSize); + return this.signValue; +}; + +/** + * Returns the raw binary exponent bits + * @return {number} + */ +tcuFloat.deFloat.prototype.exponentBits = function() { + if (typeof this.expValue === 'undefined') + this.expValue = this.getBitRange(this.description.MantissaBits, this.description.MantissaBits + this.description.ExponentBits); + return this.expValue; +}; + +/** + * Returns the raw binary mantissa bits + * @return {number} + */ +tcuFloat.deFloat.prototype.mantissaBits = function() { + if (typeof this.mantissaValue === 'undefined') + this.mantissaValue = this.getBitRange(0, this.description.MantissaBits); + return this.mantissaValue; +}; + +/** + * Returns the sign as a factor (-1 or 1) + * @return {number} + */ +tcuFloat.deFloat.prototype.sign = function() { + var sign = this.signBit(); + var signvalue = sign ? -1 : 1; + return signvalue; +}; + +/** + * Returns the real exponent, checking if it's a denorm or zero number or not + * @return {number} + */ +tcuFloat.deFloat.prototype.exponent = function() {return this.isDenorm() ? 1 - this.description.ExponentBias : this.exponentBits() - this.description.ExponentBias;}; + +/** + * Returns the (still raw) mantissa, checking if it's a denorm or zero number or not + * Makes the normally implicit bit explicit. + * @return {number} + */ +tcuFloat.deFloat.prototype.mantissa = function() {return this.isZero() || this.isDenorm() ? this.mantissaBits() : deMath.binaryOp(this.mantissaBits(), deMath.shiftLeft(1, this.description.MantissaBits), deMath.BinaryOp.OR);}; + +/** + * Returns if the number is infinity or not. + * @return {boolean} + */ +tcuFloat.deFloat.prototype.isInf = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() == 0;}; + +/** + * Returns if the number is NaN or not. + * @return {boolean} + */ +tcuFloat.deFloat.prototype.isNaN = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() != 0;}; + +/** + * Returns if the number is zero or not. + * @return {boolean} + */ +tcuFloat.deFloat.prototype.isZero = function() {return this.exponentBits() == 0 && this.mantissaBits() == 0;}; + +/** + * Returns if the number is denormalized or not. + * @return {boolean} + */ +tcuFloat.deFloat.prototype.isDenorm = function() {return this.exponentBits() == 0 && this.mantissaBits() != 0;}; + +/** + * Builds a zero float of the current binary description. + * @param {number} sign + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.zero = function(sign) { + return this.description.zero(sign); +}; + +/** + * Builds an infinity float representation of the current binary description. + * @param {number} sign + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.inf = function(sign) { + return this.description.inf(sign); +}; + +/** + * Builds a NaN float representation of the current binary description. + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.nan = function() { + return this.description.nan(); +}; + +/** + * Builds a float of the current binary description. + * Given a sign, exponent and mantissa. + * @param {number} sign + * @param {number} exponent + * @param {number} mantissa + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.construct = function(sign, exponent, mantissa) { + return this.description.construct(sign, exponent, mantissa); +}; + +/** + * Builds a float of the current binary description. + * Given a sign, exponent and a raw binary mantissa. + * @param {number} sign + * @param {number} exponent + * @param {number} mantissaBits Raw binary mantissa. + * @return {tcuFloat.deFloat} + */ +tcuFloat.deFloat.prototype.constructBits = function(sign, exponent, mantissaBits) { + return this.description.constructBits(sign, exponent, mantissaBits); +}; + +/** + * Calculates the JS float number from the internal representation. + * @return {number} The JS float value represented by this tcuFloat.deFloat. + */ +tcuFloat.deFloat.prototype.getValue = function() { + if ((this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN) === 0 && this.sign() < 0) + return 0; + if (this.isInf()) + return Number.Infinity; + if (this.isNaN()) + return Number.NaN; + if (this.isZero()) + return this.sign() * 0; + /**@type {number} */ var mymantissa = this.mantissa(); + /**@type {number} */ var myexponent = this.exponent(); + /**@type {number} */ var sign = this.sign(); + + /**@type {number} */ var value = mymantissa / Math.pow(2, this.description.MantissaBits) * Math.pow(2, myexponent); + + if (this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN != 0) + value = value * sign; + + return value; +}; + +tcuFloat.description10 = new tcuFloat.FloatDescription(5, 5, 15, 0); +tcuFloat.description11 = new tcuFloat.FloatDescription(5, 6, 15, 0); +tcuFloat.description16 = new tcuFloat.FloatDescription(5, 10, 15, tcuFloat.FloatFlags.FLOAT_HAS_SIGN); +tcuFloat.description32 = new tcuFloat.FloatDescription(8, 23, 127, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM); +tcuFloat.description64 = new tcuFloat.FloatDescription(11, 52, 1023, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM); + +tcuFloat.convertFloat32Inline = (function() { + var float32View = new Float32Array(1); + var int32View = new Int32Array(float32View.buffer); + + return function(fval, description) { + float32View[0] = fval; + var fbits = int32View[0]; + + var exponentBits = (fbits >> 23) & 0xff; + var mantissaBits = fbits & 0x7fffff; + var signBit = (fbits & 0x80000000) ? 1 : 0; + var sign = signBit ? -1 : 1; + + var isZero = exponentBits == 0 && mantissaBits == 0; + + var bitDiff; + var half; + var bias; + + if (!(description.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && sign < 0) { + // Negative number, truncate to zero. + return description.zeroNumber(+1); + } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits == 0) { // isInf + return description.infNumber(sign); + } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits != 0) { // isNaN + return description.nanNumber(); + } else if (isZero) { + return description.zeroNumber(sign); + } else { + var eMin = 1 - description.ExponentBias; + var eMax = ((1 << description.ExponentBits) - 2) - description.ExponentBias; + + var isDenorm = exponentBits == 0 && mantissaBits != 0; + + var s = signBit << (description.ExponentBits + description.MantissaBits); // \note Not sign, but sign bit. + var e = isDenorm ? 1 - tcuFloat.description32.ExponentBias : exponentBits - tcuFloat.description32.ExponentBias;// other.exponent(); + var m = isZero || isDenorm ? mantissaBits : mantissaBits | (1 << tcuFloat.description32.MantissaBits); // other.mantissa(); + + // Normalize denormalized values prior to conversion. + while (!(m & (1 << tcuFloat.description32.MantissaBits))) { + m = deMath.shiftLeft(m, 1); + e -= 1; + } + + if (e < eMin) { + // Underflow. + if ((description.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= description.MantissaBits)) { + // Shift and round (RTE). + bitDiff = (tcuFloat.description32.MantissaBits - description.MantissaBits) + (eMin - e); + half = (1 << (bitDiff - 1)) - 1; + bias = ((m >> bitDiff) & 1); + return (s | ((m + half + bias) >> bitDiff)); + } else + return description.zeroNumber(sign); + } else { + // Remove leading 1. + m = (m & ~(1 << tcuFloat.description32.MantissaBits)); + + if (description.MantissaBits < tcuFloat.description32.MantissaBits) { + // Round mantissa (round to nearest even). + bitDiff = tcuFloat.description32.MantissaBits - description.MantissaBits; + half = (1 << (bitDiff - 1)) - 1; + bias = ((m >> bitDiff) & 1); + + m = (m + half + bias) >> bitDiff; + + if ((m & (1 << description.MantissaBits))) { + // Overflow in mantissa. + m = 0; + e += 1; + } + } else { + bitDiff = description.MantissaBits - tcuFloat.description32.MantissaBits; + m = (m << bitDiff); + } + + if (e > eMax) { + // Overflow. + return description.infNumber(sign); + } else { + DE_ASSERT(deMath.deInRange32(e, eMin, eMax)); + DE_ASSERT(((e + description.ExponentBias) & ~((1 << description.ExponentBits) - 1)) == 0); + DE_ASSERT((m & ~((1 << description.MantissaBits) - 1)) == 0); + + return (s | ((e + description.ExponentBias) << description.MantissaBits)) | m; + } + } + } + }; +})(); + +/** + * Builds a 10 bit tcuFloat.deFloat + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat10 = function(value) { + DE_ASSERT(Number.isInteger(value) && value <= 0x3ff); + /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); + return tcuFloat.description10.convert(other32); +}; + +/** + * Builds a 11 bit tcuFloat.deFloat + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat11 = function(value) { + /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); + return tcuFloat.description11.convert(other32); +}; + +/** + * Builds a 16 bit tcuFloat.deFloat + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat16 = function(value) { + /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); + return tcuFloat.description16.convert(other32); +}; + +/** + * Builds a 16 bit tcuFloat.deFloat from raw bits + * @param {number} value (16-bit value) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat32From16 = function(value) { + var other16 = tcuFloat.newDeFloatFromParameters(value, tcuFloat.description16); + return tcuFloat.description32.convert(other16); +}; + +/** + * Builds a 16 bit tcuFloat.deFloat with no denorm support + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat16NoDenorm = function(value) { + /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); + return tcuFloat.description16.convert(other32); +}; + +/** + * Builds a 32 bit tcuFloat.deFloat + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat32 = function(value) { + return new tcuFloat.deFloat().deFloatNumber(value); +}; + +tcuFloat.numberToFloat11 = function(value) { + return tcuFloat.convertFloat32Inline(value, tcuFloat.description11); +}; + +tcuFloat.float11ToNumber = (function() { + var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description11); + return function(float11) { + x.deFloatParametersNumber(float11); + return x.getValue(); + }; +})(); + +tcuFloat.numberToFloat10 = function(value) { + return tcuFloat.convertFloat32Inline(value, tcuFloat.description10); +}; + +tcuFloat.float10ToNumber = (function() { + var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description10); + return function(float10) { + x.deFloatParametersNumber(float10); + return x.getValue(); + }; +})(); + +tcuFloat.numberToHalfFloat = function(value) { + return tcuFloat.convertFloat32Inline(value, tcuFloat.description16); +}; + +tcuFloat.numberToHalfFloatNoDenorm = function(value) { + return tcuFloat.newFloat16NoDenorm(value).bits(); +}; + +tcuFloat.halfFloatToNumber = (function() { + var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description16); + return function(half) { + x.deFloatParametersNumber(half); + return x.getValue(); + }; +})(); + +tcuFloat.halfFloatToNumberNoDenorm = tcuFloat.halfFloatToNumber; + +/** + * Builds a 64 bit tcuFloat.deFloat + * @param {number} value (64-bit JS float) + * @return {tcuFloat.deFloat} + */ +tcuFloat.newFloat64 = function(value) { + return new tcuFloat.deFloat().deFloatParameters(0, tcuFloat.description64) + .deFloatNumber64(value); +}; + +}); |