tcuFloat.js (30890B)
1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES Utilities 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 21 'use strict'; 22 goog.provide('framework.common.tcuFloat'); 23 goog.require('framework.delibs.debase.deMath'); 24 25 goog.scope(function() { 26 27 var tcuFloat = framework.common.tcuFloat; 28 var deMath = framework.delibs.debase.deMath; 29 30 var DE_ASSERT = function(x) { 31 if (!x) 32 throw new Error('Assert failed'); 33 }; 34 35 tcuFloat.FloatFlags = { 36 FLOAT_HAS_SIGN: (1 << 0), 37 FLOAT_SUPPORT_DENORM: (1 << 1) 38 }; 39 40 /** 41 * Defines a tcuFloat.FloatDescription object, which is an essential part of the tcuFloat.deFloat type. 42 * Holds the information that shapes the tcuFloat.deFloat. 43 * @constructor 44 */ 45 tcuFloat.FloatDescription = function(exponentBits, mantissaBits, exponentBias, flags) { 46 this.ExponentBits = exponentBits; 47 this.MantissaBits = mantissaBits; 48 this.ExponentBias = exponentBias; 49 this.Flags = flags; 50 51 this.totalBitSize = 1 + this.ExponentBits + this.MantissaBits; 52 this.totalByteSize = Math.floor(this.totalBitSize / 8) + ((this.totalBitSize % 8) > 0 ? 1 : 0); 53 }; 54 55 /** 56 * Builds a zero float of the current binary description. 57 * @param {number} sign 58 * @return {tcuFloat.deFloat} 59 */ 60 tcuFloat.FloatDescription.prototype.zero = function(sign) { 61 return tcuFloat.newDeFloatFromParameters(this.zeroNumber(sign), this); 62 }; 63 64 tcuFloat.FloatDescription.prototype.zeroNumber = function(sign) { 65 return deMath.shiftLeft((sign > 0 ? 0 : 1), (this.ExponentBits + this.MantissaBits)); 66 }; 67 68 /** 69 * Builds an infinity float representation of the current binary description. 70 * @param {number} sign 71 * @return {tcuFloat.deFloat} 72 */ 73 tcuFloat.FloatDescription.prototype.inf = function(sign) { 74 return tcuFloat.newDeFloatFromParameters(this.infNumber(sign), this); 75 }; 76 77 tcuFloat.FloatDescription.prototype.infNumber = function(sign) { 78 return ((sign > 0 ? 0 : 1) << (this.ExponentBits + this.MantissaBits)) | 79 deMath.shiftLeft(((1 << this.ExponentBits) - 1), this.MantissaBits); //Unless using very large exponent types, native shift is safe here, i guess. 80 }; 81 82 /** 83 * Builds a NaN float representation of the current binary description. 84 * @return {tcuFloat.deFloat} 85 */ 86 tcuFloat.FloatDescription.prototype.nan = function() { 87 return tcuFloat.newDeFloatFromParameters(this.nanNumber(), this); 88 }; 89 90 tcuFloat.FloatDescription.prototype.nanNumber = function() { 91 return deMath.shiftLeft(1, (this.ExponentBits + this.MantissaBits)) - 1; 92 }; 93 94 /** 95 * Builds a tcuFloat.deFloat number based on the description and the given 96 * sign, exponent and mantissa values. 97 * @param {number} sign 98 * @param {number} exponent 99 * @param {number} mantissa 100 * @return {tcuFloat.deFloat} 101 */ 102 tcuFloat.FloatDescription.prototype.construct = function(sign, exponent, mantissa) { 103 // Repurpose this otherwise invalid input as a shorthand notation for zero (no need for caller to care about internal representation) 104 /** @type {boolean} */ var isShorthandZero = exponent == 0 && mantissa == 0; 105 106 // Handles the typical notation for zero (min exponent, mantissa 0). Note that the exponent usually used exponent (-ExponentBias) for zero/subnormals is not used. 107 // Instead zero/subnormals have the (normally implicit) leading mantissa bit set to zero. 108 109 /** @type {boolean} */ var isDenormOrZero = (exponent == 1 - this.ExponentBias) && (deMath.shiftRight(mantissa, this.MantissaBits) == 0); 110 /** @type {number} */ var s = deMath.shiftLeft((sign < 0 ? 1 : 0), (this.ExponentBits + this.MantissaBits)); 111 /** @type {number} */ var exp = (isShorthandZero || isDenormOrZero) ? 0 : exponent + this.ExponentBias; 112 113 DE_ASSERT(sign == +1 || sign == -1); 114 DE_ASSERT(isShorthandZero || isDenormOrZero || deMath.shiftRight(mantissa, this.MantissaBits) == 1); 115 DE_ASSERT((exp >> this.ExponentBits) == 0); //Native shift is safe 116 117 return tcuFloat.newDeFloatFromParameters( 118 deMath.binaryOp( 119 deMath.binaryOp( 120 s, 121 deMath.shiftLeft(exp, this.MantissaBits), 122 deMath.BinaryOp.OR 123 ), 124 deMath.binaryOp( 125 mantissa, 126 deMath.shiftLeft(1, this.MantissaBits) - 1, 127 deMath.BinaryOp.AND 128 ), 129 deMath.BinaryOp.OR 130 ), 131 this 132 ); 133 }; 134 135 /** 136 * Builds a tcuFloat.deFloat number based on the description and the given 137 * sign, exponent and binary mantissa values. 138 * @param {number} sign 139 * @param {number} exponent 140 * @param {number} mantissaBits The raw binary representation. 141 * @return {tcuFloat.deFloat} 142 */ 143 tcuFloat.FloatDescription.prototype.constructBits = function(sign, exponent, mantissaBits) { 144 /** @type {number} */ var signBit = sign < 0 ? 1 : 0; 145 /** @type {number} */ var exponentBits = exponent + this.ExponentBias; 146 147 DE_ASSERT(sign == +1 || sign == -1); 148 DE_ASSERT((exponentBits >> this.ExponentBits) == 0); 149 DE_ASSERT(deMath.shiftRight(mantissaBits, this.MantissaBits) == 0); 150 151 return tcuFloat.newDeFloatFromParameters( 152 deMath.binaryOp( 153 deMath.binaryOp( 154 deMath.shiftLeft( 155 signBit, 156 this.ExponentBits + this.MantissaBits 157 ), 158 deMath.shiftLeft(exponentBits, this.MantissaBits), 159 deMath.BinaryOp.OR 160 ), 161 mantissaBits, 162 deMath.BinaryOp.OR 163 ), 164 this 165 ); 166 }; 167 168 /** 169 * Converts a tcuFloat.deFloat from it's own format description into the format described 170 * by this description. 171 * @param {tcuFloat.deFloat} other Other float to convert to this format description. 172 * @return {tcuFloat.deFloat} converted tcuFloat.deFloat 173 */ 174 tcuFloat.FloatDescription.prototype.convert = function(other) { 175 /** @type {number} */ var otherExponentBits = other.description.ExponentBits; 176 /** @type {number} */ var otherMantissaBits = other.description.MantissaBits; 177 /** @type {number} */ var otherExponentBias = other.description.ExponentBias; 178 /** @type {number} */ var otherFlags = other.description.Flags; 179 180 /** @type {number} */ var bitDiff; 181 /** @type {number} */ var half; 182 /** @type {number} */ var bias; 183 184 if (!(this.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && other.sign() < 0) { 185 // Negative number, truncate to zero. 186 return this.zero(+1); 187 } else if (other.isInf()) { 188 return this.inf(other.sign()); 189 } else if (other.isNaN()) { 190 return this.nan(); 191 } else if (other.isZero()) { 192 return this.zero(other.sign()); 193 } else { 194 /** @type {number} */ var eMin = 1 - this.ExponentBias; 195 /** @type {number} */ var eMax = ((1 << this.ExponentBits) - 2) - this.ExponentBias; 196 197 /** @type {number} */ var s = deMath.shiftLeft(other.signBit(), (this.ExponentBits + this.MantissaBits)); // \note Not sign, but sign bit. 198 /** @type {number} */ var e = other.exponent(); 199 /** @type {number} */ var m = other.mantissa(); 200 201 // Normalize denormalized values prior to conversion. 202 while (!deMath.binaryOp(m, deMath.shiftLeft(1, otherMantissaBits), deMath.BinaryOp.AND)) { 203 m = deMath.shiftLeft(m, 1); 204 e -= 1; 205 } 206 207 if (e < eMin) { 208 // Underflow. 209 if ((this.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= this.MantissaBits)) { 210 // Shift and round (RTE). 211 bitDiff = (otherMantissaBits - this.MantissaBits) + (eMin - e); 212 half = deMath.shiftLeft(1, (bitDiff - 1)) - 1; 213 bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND); 214 215 return tcuFloat.newDeFloatFromParameters( 216 deMath.binaryOp( 217 s, 218 deMath.shiftRight( 219 m + half + bias, 220 bitDiff 221 ), 222 deMath.BinaryOp.OR 223 ), 224 this 225 ); 226 } else 227 return this.zero(other.sign()); 228 } else { 229 // Remove leading 1. 230 m = deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, otherMantissaBits)), deMath.BinaryOp.AND); 231 232 if (this.MantissaBits < otherMantissaBits) { 233 // Round mantissa (round to nearest even). 234 bitDiff = otherMantissaBits - this.MantissaBits; 235 half = deMath.shiftLeft(1, (bitDiff - 1)) - 1; 236 bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND); 237 238 m = deMath.shiftRight(m + half + bias, bitDiff); 239 240 if (deMath.binaryOp(m, deMath.shiftLeft(1, this.MantissaBits), deMath.BinaryOp.AND)) { 241 // Overflow in mantissa. 242 m = 0; 243 e += 1; 244 } 245 } else { 246 bitDiff = this.MantissaBits - otherMantissaBits; 247 m = deMath.shiftLeft(m, bitDiff); 248 } 249 250 if (e > eMax) { 251 // Overflow. 252 return this.inf(other.sign()); 253 } else { 254 DE_ASSERT(deMath.deInRange32(e, eMin, eMax)); 255 DE_ASSERT(deMath.binaryOp((e + this.ExponentBias), deMath.binaryNot(deMath.shiftLeft(1, this.ExponentBits) - 1), deMath.BinaryOp.AND) == 0); 256 DE_ASSERT(deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, this.MantissaBits) - 1), deMath.BinaryOp.AND) == 0); 257 258 return tcuFloat.newDeFloatFromParameters( 259 deMath.binaryOp( 260 deMath.binaryOp( 261 s, 262 deMath.shiftLeft( 263 e + this.ExponentBias, 264 this.MantissaBits 265 ), 266 deMath.BinaryOp.OR 267 ), 268 m, 269 deMath.BinaryOp.OR 270 ), 271 this 272 ); 273 } 274 } 275 } 276 }; 277 278 /** 279 * tcuFloat.deFloat class - Empty constructor, builds a 32 bit float by default 280 * @constructor 281 */ 282 tcuFloat.deFloat = function() { 283 this.description = tcuFloat.description32; 284 285 this.m_buffer = null; 286 this.m_array = null; 287 this.m_array32 = null; 288 this.bitValue = undefined; 289 this.signValue = undefined; 290 this.expValue = undefined; 291 this.mantissaValue = undefined; 292 293 this.m_value = 0; 294 }; 295 296 /** 297 * buffer - Get the deFloat's existing ArrayBuffer or create one if none exists. 298 * @return {ArrayBuffer} 299 */ 300 tcuFloat.deFloat.prototype.buffer = function() { 301 if (!this.m_buffer) 302 this.m_buffer = new ArrayBuffer(this.description.totalByteSize); 303 return this.m_buffer; 304 }; 305 306 /** 307 * array - Get the deFloat's existing Uint8Array or create one if none exists. 308 * @return {Uint8Array} 309 */ 310 tcuFloat.deFloat.prototype.array = function() { 311 if (!this.m_array) 312 this.m_array = new Uint8Array(this.buffer()); 313 return this.m_array; 314 }; 315 316 /** 317 * array32 - Get the deFloat's existing Uint32Array or create one if none exists. 318 * @return {Uint32Array} 319 */ 320 tcuFloat.deFloat.prototype.array32 = function() { 321 if (!this.m_array32) 322 this.m_array32 = new Uint32Array(this.buffer()); 323 return this.m_array32; 324 }; 325 326 /** 327 * deFloatNumber - To be used immediately after constructor 328 * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number. 329 * @param {number} jsnumber 330 * @return {tcuFloat.deFloat} 331 */ 332 tcuFloat.deFloat.prototype.deFloatNumber = function(jsnumber) { 333 var view32 = new DataView(this.buffer()); 334 view32.setFloat32(0, jsnumber, true); //little-endian 335 this.m_value = view32.getFloat32(0, true); //little-endian 336 337 // Clear cached values 338 this.bitValue = undefined; 339 this.signValue = undefined; 340 this.expValue = undefined; 341 this.mantissaValue = undefined; 342 343 return this; 344 }; 345 346 /** 347 * deFloatNumber64 - To be used immediately after constructor 348 * Builds a 64-bit tcuFloat.deFloat based on a 64-bit JS number. 349 * @param {number} jsnumber 350 * @return {tcuFloat.deFloat} 351 */ 352 tcuFloat.deFloat.prototype.deFloatNumber64 = function(jsnumber) { 353 var view64 = new DataView(this.buffer()); 354 view64.setFloat64(0, jsnumber, true); //little-endian 355 this.m_value = view64.getFloat64(0, true); //little-endian 356 357 // Clear cached values 358 this.bitValue = undefined; 359 this.signValue = undefined; 360 this.expValue = undefined; 361 this.mantissaValue = undefined; 362 363 return this; 364 }; 365 366 /** 367 * Convenience function to build a 32-bit tcuFloat.deFloat based on a 64-bit JS number 368 * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number. 369 * @param {number} jsnumber 370 * @return {tcuFloat.deFloat} 371 */ 372 tcuFloat.newDeFloatFromNumber = function(jsnumber) { 373 return new tcuFloat.deFloat().deFloatNumber(jsnumber); 374 }; 375 376 /** 377 * deFloatBuffer - To be used immediately after constructor 378 * Builds a tcuFloat.deFloat based on a buffer and a format description. 379 * The buffer is assumed to contain data of the given description. 380 * @param {ArrayBuffer} buffer 381 * @param {tcuFloat.FloatDescription} description 382 * @return {tcuFloat.deFloat} 383 */ 384 tcuFloat.deFloat.prototype.deFloatBuffer = function(buffer, description) { 385 this.m_buffer = buffer; 386 this.m_array = new Uint8Array(this.m_buffer); 387 this.m_array32 = new Uint32Array(this.m_buffer); 388 389 this.m_value = deMath.arrayToNumber(this.m_array); 390 391 // Clear cached values 392 this.bitValue = undefined; 393 this.signValue = undefined; 394 this.expValue = undefined; 395 this.mantissaValue = undefined; 396 397 return this; 398 }; 399 400 /** 401 * Convenience function to build a tcuFloat.deFloat based on a buffer and a format description 402 * The buffer is assumed to contain data of the given description. 403 * @param {ArrayBuffer} buffer 404 * @param {tcuFloat.FloatDescription} description 405 * @return {tcuFloat.deFloat} 406 */ 407 tcuFloat.newDeFloatFromBuffer = function(buffer, description) { 408 return new tcuFloat.deFloat().deFloatBuffer(buffer, description); 409 }; 410 411 /** 412 * Set the tcuFloat.deFloat from the given bitwise representation. 413 * 414 * @param {number} jsnumber This is taken to be the bitwise representation of 415 * the floating point number represented by this deFloat. It must be an 416 * integer, less than 2^52, and compatible with the existing description. 417 * @return {tcuFloat.deFloat} 418 **/ 419 tcuFloat.deFloat.prototype.deFloatParametersNumber = function(jsnumber) { 420 /** @type {number} */ var jsnumberMax = -1 >>> (32 - this.description.totalBitSize); 421 DE_ASSERT(Number.isInteger(jsnumber) && jsnumber <= jsnumberMax); 422 423 this.m_value = jsnumber; 424 deMath.numberToArray(this.m_array, jsnumber); 425 426 // Clear cached values 427 this.bitValue = undefined; 428 this.signValue = undefined; 429 this.expValue = undefined; 430 this.mantissaValue = undefined; 431 432 return this; 433 }; 434 435 /** 436 * Initializes a tcuFloat.deFloat from the given bitwise representation, 437 * with the specified format description. 438 * 439 * @param {number} jsnumber This is taken to be the bitwise representation of 440 * the floating point number represented by this deFloat. It must be an 441 * integer, less than 2^52, and compatible with the new description. 442 * @param {tcuFloat.FloatDescription} description 443 * @return {tcuFloat.deFloat} 444 **/ 445 tcuFloat.deFloat.prototype.deFloatParameters = function(jsnumber, description) { 446 /** @type {number} */ var maxUint52 = 0x10000000000000; 447 DE_ASSERT(Number.isInteger(jsnumber) && jsnumber < maxUint52); 448 if (description.totalBitSize > 52) { 449 // The jsnumber representation for this number can't possibly be valid. 450 // Make sure it has a sentinel 0 value. 451 DE_ASSERT(jsnumber === 0); 452 } 453 454 this.description = description; 455 456 this.m_buffer = new ArrayBuffer(this.description.totalByteSize); 457 this.m_array = new Uint8Array(this.m_buffer); 458 459 return this.deFloatParametersNumber(jsnumber); 460 }; 461 462 /** 463 * Convenience function. Creates a tcuFloat.deFloat, then initializes it from 464 * the given bitwise representation, with the specified format description. 465 * 466 * @param {number} jsnumber This is taken to be the bitwise representation of 467 * the floating point number represented by this deFloat. It must be an 468 * integer, less than 2^52, and compatible with the new description. 469 * @param {tcuFloat.FloatDescription} description 470 * @return {tcuFloat.deFloat} 471 **/ 472 tcuFloat.newDeFloatFromParameters = function(jsnumber, description) { 473 return new tcuFloat.deFloat().deFloatParameters(jsnumber, description); 474 }; 475 476 /** 477 * Returns bit range [begin, end) 478 * @param {number} begin 479 * @param {number} end 480 * @return {number} 481 */ 482 tcuFloat.deFloat.prototype.getBitRange = function(begin, end) { 483 if (this.description.totalBitSize <= 52) { 484 // this.bits() is invalid for more than 52 bits. 485 return deMath.getBitRange(this.bits(), begin, end); 486 } else { 487 return deMath.getArray32BitRange(this.array32(), begin, end); 488 } 489 }; 490 491 /** 492 * Returns the raw binary representation value of the tcuFloat.deFloat 493 * @return {number} 494 */ 495 tcuFloat.deFloat.prototype.bits = function() { 496 if (typeof this.bitValue === 'undefined') 497 this.bitValue = deMath.arrayToNumber(this.array()); 498 return this.bitValue; 499 }; 500 501 /** 502 * Returns the raw binary sign bit 503 * @return {number} 504 */ 505 tcuFloat.deFloat.prototype.signBit = function() { 506 if (typeof this.signValue === 'undefined') 507 this.signValue = this.getBitRange(this.description.totalBitSize - 1, this.description.totalBitSize); 508 return this.signValue; 509 }; 510 511 /** 512 * Returns the raw binary exponent bits 513 * @return {number} 514 */ 515 tcuFloat.deFloat.prototype.exponentBits = function() { 516 if (typeof this.expValue === 'undefined') 517 this.expValue = this.getBitRange(this.description.MantissaBits, this.description.MantissaBits + this.description.ExponentBits); 518 return this.expValue; 519 }; 520 521 /** 522 * Returns the raw binary mantissa bits 523 * @return {number} 524 */ 525 tcuFloat.deFloat.prototype.mantissaBits = function() { 526 if (typeof this.mantissaValue === 'undefined') 527 this.mantissaValue = this.getBitRange(0, this.description.MantissaBits); 528 return this.mantissaValue; 529 }; 530 531 /** 532 * Returns the sign as a factor (-1 or 1) 533 * @return {number} 534 */ 535 tcuFloat.deFloat.prototype.sign = function() { 536 var sign = this.signBit(); 537 var signvalue = sign ? -1 : 1; 538 return signvalue; 539 }; 540 541 /** 542 * Returns the real exponent, checking if it's a denorm or zero number or not 543 * @return {number} 544 */ 545 tcuFloat.deFloat.prototype.exponent = function() {return this.isDenorm() ? 1 - this.description.ExponentBias : this.exponentBits() - this.description.ExponentBias;}; 546 547 /** 548 * Returns the (still raw) mantissa, checking if it's a denorm or zero number or not 549 * Makes the normally implicit bit explicit. 550 * @return {number} 551 */ 552 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);}; 553 554 /** 555 * Returns if the number is infinity or not. 556 * @return {boolean} 557 */ 558 tcuFloat.deFloat.prototype.isInf = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() == 0;}; 559 560 /** 561 * Returns if the number is NaN or not. 562 * @return {boolean} 563 */ 564 tcuFloat.deFloat.prototype.isNaN = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() != 0;}; 565 566 /** 567 * Returns if the number is zero or not. 568 * @return {boolean} 569 */ 570 tcuFloat.deFloat.prototype.isZero = function() {return this.exponentBits() == 0 && this.mantissaBits() == 0;}; 571 572 /** 573 * Returns if the number is denormalized or not. 574 * @return {boolean} 575 */ 576 tcuFloat.deFloat.prototype.isDenorm = function() {return this.exponentBits() == 0 && this.mantissaBits() != 0;}; 577 578 /** 579 * Builds a zero float of the current binary description. 580 * @param {number} sign 581 * @return {tcuFloat.deFloat} 582 */ 583 tcuFloat.deFloat.prototype.zero = function(sign) { 584 return this.description.zero(sign); 585 }; 586 587 /** 588 * Builds an infinity float representation of the current binary description. 589 * @param {number} sign 590 * @return {tcuFloat.deFloat} 591 */ 592 tcuFloat.deFloat.prototype.inf = function(sign) { 593 return this.description.inf(sign); 594 }; 595 596 /** 597 * Builds a NaN float representation of the current binary description. 598 * @return {tcuFloat.deFloat} 599 */ 600 tcuFloat.deFloat.prototype.nan = function() { 601 return this.description.nan(); 602 }; 603 604 /** 605 * Builds a float of the current binary description. 606 * Given a sign, exponent and mantissa. 607 * @param {number} sign 608 * @param {number} exponent 609 * @param {number} mantissa 610 * @return {tcuFloat.deFloat} 611 */ 612 tcuFloat.deFloat.prototype.construct = function(sign, exponent, mantissa) { 613 return this.description.construct(sign, exponent, mantissa); 614 }; 615 616 /** 617 * Builds a float of the current binary description. 618 * Given a sign, exponent and a raw binary mantissa. 619 * @param {number} sign 620 * @param {number} exponent 621 * @param {number} mantissaBits Raw binary mantissa. 622 * @return {tcuFloat.deFloat} 623 */ 624 tcuFloat.deFloat.prototype.constructBits = function(sign, exponent, mantissaBits) { 625 return this.description.constructBits(sign, exponent, mantissaBits); 626 }; 627 628 /** 629 * Calculates the JS float number from the internal representation. 630 * @return {number} The JS float value represented by this tcuFloat.deFloat. 631 */ 632 tcuFloat.deFloat.prototype.getValue = function() { 633 if ((this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN) === 0 && this.sign() < 0) 634 return 0; 635 if (this.isInf()) 636 return Number.Infinity; 637 if (this.isNaN()) 638 return Number.NaN; 639 if (this.isZero()) 640 return this.sign() * 0; 641 /**@type {number} */ var mymantissa = this.mantissa(); 642 /**@type {number} */ var myexponent = this.exponent(); 643 /**@type {number} */ var sign = this.sign(); 644 645 /**@type {number} */ var value = mymantissa / Math.pow(2, this.description.MantissaBits) * Math.pow(2, myexponent); 646 647 if (this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN != 0) 648 value = value * sign; 649 650 return value; 651 }; 652 653 tcuFloat.description10 = new tcuFloat.FloatDescription(5, 5, 15, 0); 654 tcuFloat.description11 = new tcuFloat.FloatDescription(5, 6, 15, 0); 655 tcuFloat.description16 = new tcuFloat.FloatDescription(5, 10, 15, tcuFloat.FloatFlags.FLOAT_HAS_SIGN); 656 tcuFloat.description32 = new tcuFloat.FloatDescription(8, 23, 127, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM); 657 tcuFloat.description64 = new tcuFloat.FloatDescription(11, 52, 1023, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM); 658 659 tcuFloat.convertFloat32Inline = (function() { 660 var float32View = new Float32Array(1); 661 var int32View = new Int32Array(float32View.buffer); 662 663 return function(fval, description) { 664 float32View[0] = fval; 665 var fbits = int32View[0]; 666 667 var exponentBits = (fbits >> 23) & 0xff; 668 var mantissaBits = fbits & 0x7fffff; 669 var signBit = (fbits & 0x80000000) ? 1 : 0; 670 var sign = signBit ? -1 : 1; 671 672 var isZero = exponentBits == 0 && mantissaBits == 0; 673 674 var bitDiff; 675 var half; 676 var bias; 677 678 if (!(description.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && sign < 0) { 679 // Negative number, truncate to zero. 680 return description.zeroNumber(+1); 681 } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits == 0) { // isInf 682 return description.infNumber(sign); 683 } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits != 0) { // isNaN 684 return description.nanNumber(); 685 } else if (isZero) { 686 return description.zeroNumber(sign); 687 } else { 688 var eMin = 1 - description.ExponentBias; 689 var eMax = ((1 << description.ExponentBits) - 2) - description.ExponentBias; 690 691 var isDenorm = exponentBits == 0 && mantissaBits != 0; 692 693 var s = signBit << (description.ExponentBits + description.MantissaBits); // \note Not sign, but sign bit. 694 var e = isDenorm ? 1 - tcuFloat.description32.ExponentBias : exponentBits - tcuFloat.description32.ExponentBias;// other.exponent(); 695 var m = isZero || isDenorm ? mantissaBits : mantissaBits | (1 << tcuFloat.description32.MantissaBits); // other.mantissa(); 696 697 // Normalize denormalized values prior to conversion. 698 while (!(m & (1 << tcuFloat.description32.MantissaBits))) { 699 m = deMath.shiftLeft(m, 1); 700 e -= 1; 701 } 702 703 if (e < eMin) { 704 // Underflow. 705 if ((description.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= description.MantissaBits)) { 706 // Shift and round (RTE). 707 bitDiff = (tcuFloat.description32.MantissaBits - description.MantissaBits) + (eMin - e); 708 half = (1 << (bitDiff - 1)) - 1; 709 bias = ((m >> bitDiff) & 1); 710 return (s | ((m + half + bias) >> bitDiff)); 711 } else 712 return description.zeroNumber(sign); 713 } else { 714 // Remove leading 1. 715 m = (m & ~(1 << tcuFloat.description32.MantissaBits)); 716 717 if (description.MantissaBits < tcuFloat.description32.MantissaBits) { 718 // Round mantissa (round to nearest even). 719 bitDiff = tcuFloat.description32.MantissaBits - description.MantissaBits; 720 half = (1 << (bitDiff - 1)) - 1; 721 bias = ((m >> bitDiff) & 1); 722 723 m = (m + half + bias) >> bitDiff; 724 725 if ((m & (1 << description.MantissaBits))) { 726 // Overflow in mantissa. 727 m = 0; 728 e += 1; 729 } 730 } else { 731 bitDiff = description.MantissaBits - tcuFloat.description32.MantissaBits; 732 m = (m << bitDiff); 733 } 734 735 if (e > eMax) { 736 // Overflow. 737 return description.infNumber(sign); 738 } else { 739 DE_ASSERT(deMath.deInRange32(e, eMin, eMax)); 740 DE_ASSERT(((e + description.ExponentBias) & ~((1 << description.ExponentBits) - 1)) == 0); 741 DE_ASSERT((m & ~((1 << description.MantissaBits) - 1)) == 0); 742 743 return (s | ((e + description.ExponentBias) << description.MantissaBits)) | m; 744 } 745 } 746 } 747 }; 748 })(); 749 750 /** 751 * Builds a 10 bit tcuFloat.deFloat 752 * @param {number} value (64-bit JS float) 753 * @return {tcuFloat.deFloat} 754 */ 755 tcuFloat.newFloat10 = function(value) { 756 DE_ASSERT(Number.isInteger(value) && value <= 0x3ff); 757 /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); 758 return tcuFloat.description10.convert(other32); 759 }; 760 761 /** 762 * Builds a 11 bit tcuFloat.deFloat 763 * @param {number} value (64-bit JS float) 764 * @return {tcuFloat.deFloat} 765 */ 766 tcuFloat.newFloat11 = function(value) { 767 /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); 768 return tcuFloat.description11.convert(other32); 769 }; 770 771 /** 772 * Builds a 16 bit tcuFloat.deFloat 773 * @param {number} value (64-bit JS float) 774 * @return {tcuFloat.deFloat} 775 */ 776 tcuFloat.newFloat16 = function(value) { 777 /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); 778 return tcuFloat.description16.convert(other32); 779 }; 780 781 /** 782 * Builds a 16 bit tcuFloat.deFloat from raw bits 783 * @param {number} value (16-bit value) 784 * @return {tcuFloat.deFloat} 785 */ 786 tcuFloat.newFloat32From16 = function(value) { 787 var other16 = tcuFloat.newDeFloatFromParameters(value, tcuFloat.description16); 788 return tcuFloat.description32.convert(other16); 789 }; 790 791 /** 792 * Builds a 16 bit tcuFloat.deFloat with no denorm support 793 * @param {number} value (64-bit JS float) 794 * @return {tcuFloat.deFloat} 795 */ 796 tcuFloat.newFloat16NoDenorm = function(value) { 797 /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value); 798 return tcuFloat.description16.convert(other32); 799 }; 800 801 /** 802 * Builds a 32 bit tcuFloat.deFloat 803 * @param {number} value (64-bit JS float) 804 * @return {tcuFloat.deFloat} 805 */ 806 tcuFloat.newFloat32 = function(value) { 807 return new tcuFloat.deFloat().deFloatNumber(value); 808 }; 809 810 tcuFloat.numberToFloat11 = function(value) { 811 return tcuFloat.convertFloat32Inline(value, tcuFloat.description11); 812 }; 813 814 tcuFloat.float11ToNumber = (function() { 815 var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description11); 816 return function(float11) { 817 x.deFloatParametersNumber(float11); 818 return x.getValue(); 819 }; 820 })(); 821 822 tcuFloat.numberToFloat10 = function(value) { 823 return tcuFloat.convertFloat32Inline(value, tcuFloat.description10); 824 }; 825 826 tcuFloat.float10ToNumber = (function() { 827 var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description10); 828 return function(float10) { 829 x.deFloatParametersNumber(float10); 830 return x.getValue(); 831 }; 832 })(); 833 834 tcuFloat.numberToHalfFloat = function(value) { 835 return tcuFloat.convertFloat32Inline(value, tcuFloat.description16); 836 }; 837 838 tcuFloat.numberToHalfFloatNoDenorm = function(value) { 839 return tcuFloat.newFloat16NoDenorm(value).bits(); 840 }; 841 842 tcuFloat.halfFloatToNumber = (function() { 843 var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description16); 844 return function(half) { 845 x.deFloatParametersNumber(half); 846 return x.getValue(); 847 }; 848 })(); 849 850 tcuFloat.halfFloatToNumberNoDenorm = tcuFloat.halfFloatToNumber; 851 852 /** 853 * Builds a 64 bit tcuFloat.deFloat 854 * @param {number} value (64-bit JS float) 855 * @return {tcuFloat.deFloat} 856 */ 857 tcuFloat.newFloat64 = function(value) { 858 return new tcuFloat.deFloat().deFloatParameters(0, tcuFloat.description64) 859 .deFloatNumber64(value); 860 }; 861 862 });