Repository: evanw/float-toy
Branch: gh-pages
Commit: 1ea0d374417b
Files: 3
Total size: 59.1 KB
Directory structure:
gitextract_qxpuqoni/
├── README.md
├── float16.js
└── index.html
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# Float Toy
Visit [http://evanw.github.io/float-toy/](http://evanw.github.io/float-toy/) to play around.
Use this to build intuition for the IEEE floating-point format.
================================================
FILE: float16.js
================================================
/**
* @petamoriken/float16 aa4af43 | MIT License - https://git.io/float16
*
* @license
* lodash-es v4.17.15 | MIT License - https://lodash.com/custom-builds
*/
var float16 = (function (exports) {
'use strict';
// algorithm: ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf
const buffer = new ArrayBuffer(4);
const floatView = new Float32Array(buffer);
const uint32View = new Uint32Array(buffer);
const baseTable = new Uint32Array(512);
const shiftTable = new Uint32Array(512);
for (let i = 0; i < 256; ++i) {
const e = i - 127; // very small number (0, -0)
if (e < -27) {
baseTable[i | 0x000] = 0x0000;
baseTable[i | 0x100] = 0x8000;
shiftTable[i | 0x000] = 24;
shiftTable[i | 0x100] = 24; // small number (denorm)
} else if (e < -14) {
baseTable[i | 0x000] = 0x0400 >> -e - 14;
baseTable[i | 0x100] = 0x0400 >> -e - 14 | 0x8000;
shiftTable[i | 0x000] = -e - 1;
shiftTable[i | 0x100] = -e - 1; // normal number
} else if (e <= 15) {
baseTable[i | 0x000] = e + 15 << 10;
baseTable[i | 0x100] = e + 15 << 10 | 0x8000;
shiftTable[i | 0x000] = 13;
shiftTable[i | 0x100] = 13; // large number (Infinity, -Infinity)
} else if (e < 128) {
baseTable[i | 0x000] = 0x7c00;
baseTable[i | 0x100] = 0xfc00;
shiftTable[i | 0x000] = 24;
shiftTable[i | 0x100] = 24; // stay (NaN, Infinity, -Infinity)
} else {
baseTable[i | 0x000] = 0x7c00;
baseTable[i | 0x100] = 0xfc00;
shiftTable[i | 0x000] = 13;
shiftTable[i | 0x100] = 13;
}
}
/**
* round a number to a half float number bits.
* @param {number} num
*/
function roundToFloat16Bits(num) {
floatView[0] = num;
const f = uint32View[0];
const e = f >> 23 & 0x1ff;
return baseTable[e] + ((f & 0x007fffff) >> shiftTable[e]);
}
const mantissaTable = new Uint32Array(2048);
const exponentTable = new Uint32Array(64);
const offsetTable = new Uint32Array(64);
mantissaTable[0] = 0;
for (let i = 1; i < 1024; ++i) {
let m = i << 13; // zero pad mantissa bits
let e = 0; // zero exponent
// normalized
while ((m & 0x00800000) === 0) {
e -= 0x00800000; // decrement exponent
m <<= 1;
}
m &= ~0x00800000; // clear leading 1 bit
e += 0x38800000; // adjust bias
mantissaTable[i] = m | e;
}
for (let i = 1024; i < 2048; ++i) {
mantissaTable[i] = 0x38000000 + (i - 1024 << 13);
}
exponentTable[0] = 0;
for (let i = 1; i < 31; ++i) {
exponentTable[i] = i << 23;
}
exponentTable[31] = 0x47800000;
exponentTable[32] = 0x80000000;
for (let i = 33; i < 63; ++i) {
exponentTable[i] = 0x80000000 + (i - 32 << 23);
}
exponentTable[63] = 0xc7800000;
offsetTable[0] = 0;
for (let i = 1; i < 64; ++i) {
if (i === 32) {
offsetTable[i] = 0;
} else {
offsetTable[i] = 1024;
}
}
/**
* convert a half float number bits to a number.
* @param {number} float16bits - half float number bits
*/
function convertToNumber(float16bits) {
const m = float16bits >> 10;
uint32View[0] = mantissaTable[offsetTable[m] + (float16bits & 0x3ff)] + exponentTable[m];
return floatView[0];
}
/**
* returns the nearest half precision float representation of a number.
* @param {number} num
*/
function hfround(num) {
num = Number(num); // for optimization
if (!Number.isFinite(num) || num === 0) {
return num;
}
const x16 = roundToFloat16Bits(num);
return convertToNumber(x16);
}
function ToInteger(num) {
if (typeof num !== "number") num = Number(num);
if (Number.isNaN(num)) num = 0;
return Math.trunc(num);
}
function defaultCompareFunction(x, y) {
const [isNaN_x, isNaN_y] = [Number.isNaN(x), Number.isNaN(y)];
if (isNaN_x && isNaN_y) return 0;
if (isNaN_x) return 1;
if (isNaN_y) return -1;
if (x < y) return -1;
if (x > y) return 1;
if (x === 0 && y === 0) {
const [isPlusZero_x, isPlusZero_y] = [Object.is(x, 0), Object.is(y, 0)];
if (!isPlusZero_x && isPlusZero_y) return -1;
if (isPlusZero_x && !isPlusZero_y) return 1;
}
return 0;
}
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/** Built-in value references. */
var Symbol$1 = root.Symbol;
/** Used for built-in method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/** Built-in value references. */
var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined;
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag),
tag = value[symToStringTag];
try {
value[symToStringTag] = undefined;
var unmasked = true;
} catch (e) {}
var result = nativeObjectToString.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag;
} else {
delete value[symToStringTag];
}
}
return result;
}
/** Used for built-in method references. */
var objectProto$1 = Object.prototype;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString$1 = objectProto$1.toString;
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString$1.call(value);
}
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
/** Built-in value references. */
var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return symToStringTag$1 && symToStringTag$1 in Object(value) ? getRawTag(value) : objectToString(value);
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
var arrayBufferTag = '[object ArrayBuffer]';
/**
* The base implementation of `_.isArrayBuffer` without Node.js optimizations.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
*/
function baseIsArrayBuffer(value) {
return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
}
/**
* The base implementation of `_.unary` without support for storing metadata.
*
* @private
* @param {Function} func The function to cap arguments for.
* @returns {Function} Returns the new capped function.
*/
function baseUnary(func) {
return function (value) {
return func(value);
};
}
/** Detect free variable `exports`. */
var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
/** Detect free variable `module`. */
var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
/** Detect the popular CommonJS extension `module.exports`. */
var moduleExports = freeModule && freeModule.exports === freeExports;
/** Detect free variable `process` from Node.js. */
var freeProcess = moduleExports && freeGlobal.process;
/** Used to access faster Node.js helpers. */
var nodeUtil = function () {
try {
// Use `util.types` for Node.js 10+.
var types = freeModule && freeModule.require && freeModule.require('util').types;
if (types) {
return types;
} // Legacy `process.binding('util')` for Node.js < 10.
return freeProcess && freeProcess.binding && freeProcess.binding('util');
} catch (e) {}
}();
/* Node.js helper references. */
var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer;
/**
* Checks if `value` is classified as an `ArrayBuffer` object.
*
* @static
* @memberOf _
* @since 4.3.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
* @example
*
* _.isArrayBuffer(new ArrayBuffer(2));
* // => true
*
* _.isArrayBuffer(new Array(2));
* // => false
*/
var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
function isDataView(view) {
return view instanceof DataView;
}
function isStringNumberKey(key) {
return typeof key === "string" && key === ToInteger(key) + "";
}
function createPrivateStorage() {
const wm = new WeakMap();
return self => {
let obj = wm.get(self);
if (obj) {
return obj;
} else {
obj = Object.create(null);
wm.set(self, obj);
return obj;
}
};
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
/** `Object#toString` result references. */
var asyncTag = '[object AsyncFunction]',
funcTag = '[object Function]',
genTag = '[object GeneratorFunction]',
proxyTag = '[object Proxy]';
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
if (!isObject(value)) {
return false;
} // The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 9 which returns 'object' for typed arrays and other constructors.
var tag = baseGetTag(value);
return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
}
/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];
/** Used to detect methods masquerading as native. */
var maskSrcKey = function () {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? 'Symbol(src)_1.' + uid : '';
}();
/**
* Checks if `func` has its source masked.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` is masked, else `false`.
*/
function isMasked(func) {
return !!maskSrcKey && maskSrcKey in func;
}
/** Used for built-in method references. */
var funcProto = Function.prototype;
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/**
* Converts `func` to its source code.
*
* @private
* @param {Function} func The function to convert.
* @returns {string} Returns the source code.
*/
function toSource(func) {
if (func != null) {
try {
return funcToString.call(func);
} catch (e) {}
try {
return func + '';
} catch (e) {}
}
return '';
}
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Used for built-in method references. */
var funcProto$1 = Function.prototype,
objectProto$2 = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var funcToString$1 = funcProto$1.toString;
/** Used to check objects for own properties. */
var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' + funcToString$1.call(hasOwnProperty$1).replace(reRegExpChar, '\\$&').replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
/**
* The base implementation of `_.isNative` without bad shim checks.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
*/
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = getValue(object, key);
return baseIsNative(value) ? value : undefined;
}
/* Built-in method references that are verified to be native. */
var nativeCreate = getNative(Object, 'create');
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
this.size = 0;
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
var result = this.has(key) && delete this.__data__[key];
this.size -= result ? 1 : 0;
return result;
}
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** Used for built-in method references. */
var objectProto$3 = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty$2 = objectProto$3.hasOwnProperty;
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty$2.call(data, key) ? data[key] : undefined;
}
/** Used for built-in method references. */
var objectProto$4 = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty$3 = objectProto$4.hasOwnProperty;
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? data[key] !== undefined : hasOwnProperty$3.call(data, key);
}
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
this.size += this.has(key) ? 0 : 1;
data[key] = nativeCreate && value === undefined ? HASH_UNDEFINED$1 : value;
return this;
}
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
} // Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
this.size = 0;
}
/**
* Performs a
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* comparison between two values to determine if they are equivalent.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.eq(object, object);
* // => true
*
* _.eq(object, other);
* // => false
*
* _.eq('a', 'a');
* // => true
*
* _.eq('a', Object('a'));
* // => false
*
* _.eq(NaN, NaN);
* // => true
*/
function eq(value, other) {
return value === other || value !== value && other !== other;
}
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
/** Used for built-in method references. */
var arrayProto = Array.prototype;
/** Built-in value references. */
var splice = arrayProto.splice;
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
--this.size;
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function listCacheHas(key) {
return assocIndexOf(this.__data__, key) > -1;
}
/**
* Sets the list cache `key` to `value`.
*
* @private
* @name set
* @memberOf ListCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the list cache instance.
*/
function listCacheSet(key, value) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
++this.size;
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
} // Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map');
/**
* Removes all key-value entries from the map.
*
* @private
* @name clear
* @memberOf MapCache
*/
function mapCacheClear() {
this.size = 0;
this.__data__ = {
'hash': new Hash(),
'map': new (Map || ListCache)(),
'string': new Hash()
};
}
/**
* Checks if `value` is suitable for use as unique object key.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
*/
function isKeyable(value) {
var type = typeof value;
return type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean' ? value !== '__proto__' : value === null;
}
/**
* Gets the data for `map`.
*
* @private
* @param {Object} map The map to query.
* @param {string} key The reference key.
* @returns {*} Returns the map data.
*/
function getMapData(map, key) {
var data = map.__data__;
return isKeyable(key) ? data[typeof key == 'string' ? 'string' : 'hash'] : data.map;
}
/**
* Removes `key` and its value from the map.
*
* @private
* @name delete
* @memberOf MapCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function mapCacheDelete(key) {
var result = getMapData(this, key)['delete'](key);
this.size -= result ? 1 : 0;
return result;
}
/**
* Gets the map value for `key`.
*
* @private
* @name get
* @memberOf MapCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function mapCacheGet(key) {
return getMapData(this, key).get(key);
}
/**
* Checks if a map value for `key` exists.
*
* @private
* @name has
* @memberOf MapCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function mapCacheHas(key) {
return getMapData(this, key).has(key);
}
/**
* Sets the map `key` to `value`.
*
* @private
* @name set
* @memberOf MapCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
function mapCacheSet(key, value) {
var data = getMapData(this, key),
size = data.size;
data.set(key, value);
this.size += data.size == size ? 0 : 1;
return this;
}
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
} // Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
/** Error message constants. */
var FUNC_ERROR_TEXT = 'Expected a function';
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* provided, it determines the cache key for storing the result based on the
* arguments provided to the memoized function. By default, the first argument
* provided to the memoized function is used as the map cache key. The `func`
* is invoked with the `this` binding of the memoized function.
*
* **Note:** The cache is exposed as the `cache` property on the memoized
* function. Its creation may be customized by replacing the `_.memoize.Cache`
* constructor with one whose instances implement the
* [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
* method interface of `clear`, `delete`, `get`, `has`, and `set`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] The function to resolve the cache key.
* @returns {Function} Returns the new memoized function.
* @example
*
* var object = { 'a': 1, 'b': 2 };
* var other = { 'c': 3, 'd': 4 };
*
* var values = _.memoize(_.values);
* values(object);
* // => [1, 2]
*
* values(other);
* // => [3, 4]
*
* object.a = 2;
* values(object);
* // => [1, 2]
*
* // Modify the result cache.
* values.cache.set(object, ['a', 'b']);
* values(object);
* // => ['a', 'b']
*
* // Replace `_.memoize.Cache`.
* _.memoize.Cache = WeakMap;
*/
function memoize(func, resolver) {
if (typeof func != 'function' || resolver != null && typeof resolver != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
var memoized = function memoized() {
var args = arguments,
key = resolver ? resolver.apply(this, args) : args[0],
cache = memoized.cache;
if (cache.has(key)) {
return cache.get(key);
}
var result = func.apply(this, args);
memoized.cache = cache.set(key, result) || cache;
return result;
};
memoized.cache = new (memoize.Cache || MapCache)();
return memoized;
} // Expose `MapCache`.
memoize.Cache = MapCache;
// JavaScriptCore bug: https://bugs.webkit.org/show_bug.cgi?id=171606
const isTypedArrayIndexedPropertyWritable = Object.getOwnPropertyDescriptor(new Uint8Array(1), 0).writable;
const _ = createPrivateStorage();
function isFloat16Array(target) {
return target instanceof Float16Array;
}
function assertFloat16Array(target) {
if (!isFloat16Array(target)) {
throw new TypeError("This is not a Float16Array");
}
}
function isDefaultFloat16ArrayMethods(target) {
return typeof target === "function" && defaultFloat16ArrayMethods.has(target);
}
function copyToArray(float16bits) {
const length = float16bits.length;
const array = new Array(length);
for (let i = 0; i < length; ++i) {
array[i] = convertToNumber(float16bits[i]);
}
return array;
} // proxy handler
const applyHandler = {
apply(func, thisArg, args) {
// peel off proxy
if (isFloat16Array(thisArg) && isDefaultFloat16ArrayMethods(func)) return Reflect.apply(func, _(thisArg).target, args);
return Reflect.apply(func, thisArg, args);
}
};
const handler = {
get(target, key) {
let wrapper = null;
if (!isTypedArrayIndexedPropertyWritable) {
wrapper = target;
target = _(wrapper).target;
}
if (isStringNumberKey(key)) {
return Reflect.has(target, key) ? convertToNumber(Reflect.get(target, key)) : undefined;
} else {
const ret = wrapper !== null && Reflect.has(wrapper, key) ? Reflect.get(wrapper, key) : Reflect.get(target, key);
if (typeof ret !== "function") return ret; // TypedArray methods can't be called by Proxy Object
let proxy = _(ret).proxy;
if (proxy === undefined) {
proxy = _(ret).proxy = new Proxy(ret, applyHandler);
}
return proxy;
}
},
set(target, key, value) {
let wrapper = null;
if (!isTypedArrayIndexedPropertyWritable) {
wrapper = target;
target = _(wrapper).target;
}
if (isStringNumberKey(key)) {
return Reflect.set(target, key, roundToFloat16Bits(value));
} else {
// frozen object can't change prototype property
if (wrapper !== null && (!Reflect.has(target, key) || Object.isFrozen(wrapper))) {
return Reflect.set(wrapper, key, value);
} else {
return Reflect.set(target, key, value);
}
}
}
};
if (!isTypedArrayIndexedPropertyWritable) {
handler.getPrototypeOf = wrapper => Reflect.getPrototypeOf(_(wrapper).target);
handler.setPrototypeOf = (wrapper, prototype) => Reflect.setPrototypeOf(_(wrapper).target, prototype);
handler.defineProperty = (wrapper, key, descriptor) => {
const target = _(wrapper).target;
return !Reflect.has(target, key) || Object.isFrozen(wrapper) ? Reflect.defineProperty(wrapper, key, descriptor) : Reflect.defineProperty(target, key, descriptor);
};
handler.deleteProperty = (wrapper, key) => {
const target = _(wrapper).target;
return Reflect.has(wrapper, key) ? Reflect.deleteProperty(wrapper, key) : Reflect.deleteProperty(target, key);
};
handler.has = (wrapper, key) => Reflect.has(wrapper, key) || Reflect.has(_(wrapper).target, key);
handler.isExtensible = wrapper => Reflect.isExtensible(wrapper);
handler.preventExtensions = wrapper => Reflect.preventExtensions(wrapper);
handler.getOwnPropertyDescriptor = (wrapper, key) => Reflect.getOwnPropertyDescriptor(wrapper, key);
handler.ownKeys = wrapper => Reflect.ownKeys(wrapper);
}
class Float16Array extends Uint16Array {
constructor(input, byteOffset, length) {
// input Float16Array
if (isFloat16Array(input)) {
super(_(input).target); // 22.2.1.3, 22.2.1.4 TypedArray, Array, ArrayLike, Iterable
} else if (input !== null && typeof input === "object" && !isArrayBuffer(input)) {
// if input is not ArrayLike and Iterable, get Array
const arrayLike = !Reflect.has(input, "length") && input[Symbol.iterator] !== undefined ? [...input] : input;
const length = arrayLike.length;
super(length);
for (let i = 0; i < length; ++i) {
// super (Uint16Array)
this[i] = roundToFloat16Bits(arrayLike[i]);
} // 22.2.1.2, 22.2.1.5 primitive, ArrayBuffer
} else {
switch (arguments.length) {
case 0:
super();
break;
case 1:
super(input);
break;
case 2:
super(input, byteOffset);
break;
case 3:
super(input, byteOffset, length);
break;
default:
super(...arguments);
}
}
let proxy;
if (isTypedArrayIndexedPropertyWritable) {
proxy = new Proxy(this, handler);
} else {
const wrapper = Object.create(null);
_(wrapper).target = this;
proxy = new Proxy(wrapper, handler);
} // proxy private storage
_(proxy).target = this; // this private storage
_(this).proxy = proxy;
return proxy;
} // static methods
static from(src) {
if ((arguments.length <= 1 ? 0 : arguments.length - 1) === 0) return new Float16Array(Uint16Array.from(src, roundToFloat16Bits).buffer);
const mapFunc = arguments.length <= 1 ? undefined : arguments[1];
const thisArg = arguments.length <= 2 ? undefined : arguments[2];
return new Float16Array(Uint16Array.from(src, function (val) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
return roundToFloat16Bits(mapFunc.call(this, val, ...args));
}, thisArg).buffer);
}
static of() {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return new Float16Array(args);
} // iterate methods
*[Symbol.iterator]() {
for (const val of super[Symbol.iterator]()) {
yield convertToNumber(val);
}
}
keys() {
return super.keys();
}
*values() {
for (const val of super.values()) {
yield convertToNumber(val);
}
}
*entries() {
for (const [i, val] of super.entries()) {
yield [i, convertToNumber(val)];
}
} // functional methods
map(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
const array = [];
for (let i = 0, l = this.length; i < l; ++i) {
const val = convertToNumber(this[i]);
array.push(callback.call(thisArg, val, i, _(this).proxy));
}
return new Float16Array(array);
}
filter(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
const array = [];
for (let i = 0, l = this.length; i < l; ++i) {
const val = convertToNumber(this[i]);
if (callback.call(thisArg, val, i, _(this).proxy)) {
array.push(val);
}
}
return new Float16Array(array);
}
reduce(callback) {
assertFloat16Array(this);
let val, start;
if ((arguments.length <= 1 ? 0 : arguments.length - 1) === 0) {
val = convertToNumber(this[0]);
start = 1;
} else {
val = arguments.length <= 1 ? undefined : arguments[1];
start = 0;
}
for (let i = start, l = this.length; i < l; ++i) {
val = callback(val, convertToNumber(this[i]), i, _(this).proxy);
}
return val;
}
reduceRight(callback) {
assertFloat16Array(this);
let val, start;
const length = this.length;
if ((arguments.length <= 1 ? 0 : arguments.length - 1) === 0) {
val = convertToNumber(this[length - 1]);
start = length - 1;
} else {
val = arguments.length <= 1 ? undefined : arguments[1];
start = length;
}
for (let i = start; i--;) {
val = callback(val, convertToNumber(this[i]), i, _(this).proxy);
}
return val;
}
forEach(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
for (let i = 0, l = this.length; i < l; ++i) {
callback.call(thisArg, convertToNumber(this[i]), i, _(this).proxy);
}
}
find(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
for (let i = 0, l = this.length; i < l; ++i) {
const value = convertToNumber(this[i]);
if (callback.call(thisArg, value, i, _(this).proxy)) return value;
}
}
findIndex(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
for (let i = 0, l = this.length; i < l; ++i) {
const value = convertToNumber(this[i]);
if (callback.call(thisArg, value, i, _(this).proxy)) return i;
}
return -1;
}
every(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
for (let i = 0, l = this.length; i < l; ++i) {
if (!callback.call(thisArg, convertToNumber(this[i]), i, _(this).proxy)) return false;
}
return true;
}
some(callback) {
assertFloat16Array(this);
const thisArg = arguments.length <= 1 ? undefined : arguments[1];
for (let i = 0, l = this.length; i < l; ++i) {
if (callback.call(thisArg, convertToNumber(this[i]), i, _(this).proxy)) return true;
}
return false;
} // change element methods
set(input) {
assertFloat16Array(this);
const offset = arguments.length <= 1 ? undefined : arguments[1];
let float16bits; // input Float16Array
if (isFloat16Array(input)) {
float16bits = _(input).target; // input others
} else {
const arrayLike = !Reflect.has(input, "length") && input[Symbol.iterator] !== undefined ? [...input] : input;
const length = arrayLike.length;
float16bits = new Uint16Array(length);
for (let i = 0, l = arrayLike.length; i < l; ++i) {
float16bits[i] = roundToFloat16Bits(arrayLike[i]);
}
}
super.set(float16bits, offset);
}
reverse() {
assertFloat16Array(this);
super.reverse();
return _(this).proxy;
}
fill(value) {
assertFloat16Array(this);
for (var _len3 = arguments.length, opts = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
opts[_key3 - 1] = arguments[_key3];
}
super.fill(roundToFloat16Bits(value), ...opts);
return _(this).proxy;
}
copyWithin(target, start) {
assertFloat16Array(this);
for (var _len4 = arguments.length, opts = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) {
opts[_key4 - 2] = arguments[_key4];
}
super.copyWithin(target, start, ...opts);
return _(this).proxy;
}
sort() {
assertFloat16Array(this);
let compareFunction = arguments.length <= 0 ? undefined : arguments[0];
if (compareFunction === undefined) {
compareFunction = defaultCompareFunction;
}
const _convertToNumber = memoize(convertToNumber);
super.sort((x, y) => compareFunction(_convertToNumber(x), _convertToNumber(y)));
return _(this).proxy;
} // copy element methods
slice() {
assertFloat16Array(this);
let float16bits; // V8, SpiderMonkey, JavaScriptCore, Chakra throw TypeError
try {
float16bits = super.slice(...arguments);
} catch (e) {
if (e instanceof TypeError) {
const uint16 = new Uint16Array(this.buffer, this.byteOffset, this.length);
float16bits = uint16.slice(...arguments);
} else {
throw e;
}
}
return new Float16Array(float16bits.buffer);
}
subarray() {
assertFloat16Array(this);
let float16bits; // V8, SpiderMonkey, JavaScriptCore, Chakra throw TypeError
try {
float16bits = super.subarray(...arguments);
} catch (e) {
if (e instanceof TypeError) {
const uint16 = new Uint16Array(this.buffer, this.byteOffset, this.length);
float16bits = uint16.subarray(...arguments);
} else {
throw e;
}
}
return new Float16Array(float16bits.buffer, float16bits.byteOffset, float16bits.length);
} // contains methods
indexOf(element) {
assertFloat16Array(this);
const length = this.length;
let from = ToInteger(arguments.length <= 1 ? undefined : arguments[1]);
if (from < 0) {
from += length;
if (from < 0) from = 0;
}
for (let i = from, l = length; i < l; ++i) {
if (convertToNumber(this[i]) === element) return i;
}
return -1;
}
lastIndexOf(element) {
assertFloat16Array(this);
const length = this.length;
let from = ToInteger(arguments.length <= 1 ? undefined : arguments[1]);
from = from === 0 ? length : from + 1;
if (from >= 0) {
from = from < length ? from : length;
} else {
from += length;
}
for (let i = from; i--;) {
if (convertToNumber(this[i]) === element) return i;
}
return -1;
}
includes(element) {
assertFloat16Array(this);
const length = this.length;
let from = ToInteger(arguments.length <= 1 ? undefined : arguments[1]);
if (from < 0) {
from += length;
if (from < 0) from = 0;
}
const isNaN = Number.isNaN(element);
for (let i = from, l = length; i < l; ++i) {
const value = convertToNumber(this[i]);
if (isNaN && Number.isNaN(value)) return true;
if (value === element) return true;
}
return false;
} // string methods
join() {
assertFloat16Array(this);
const array = copyToArray(this);
return array.join(...arguments);
}
toLocaleString() {
assertFloat16Array(this);
const array = copyToArray(this);
return array.toLocaleString(...arguments);
}
get [Symbol.toStringTag]() {
if (isFloat16Array(this)) return "Float16Array";
}
}
const Float16Array$prototype = Float16Array.prototype;
const defaultFloat16ArrayMethods = new WeakSet();
for (const key of Reflect.ownKeys(Float16Array$prototype)) {
const val = Float16Array$prototype[key];
if (typeof val === "function") defaultFloat16ArrayMethods.add(val);
}
/**
* returns an unsigned 16-bit float at the specified byte offset from the start of the DataView.
* @param {DataView} dataView
* @param {nunmber} byteOffset
* @param {*} opts
*/
function getFloat16(dataView, byteOffset) {
if (!isDataView(dataView)) throw new TypeError("First argument to getFloat16 function must be a DataView");
for (var _len = arguments.length, opts = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
opts[_key - 2] = arguments[_key];
}
return convertToNumber(dataView.getUint16(byteOffset, ...opts));
}
/**
* stores an unsigned 16-bit float value at the specified byte offset from the start of the DataView.
* @param {DataView} dataView
* @param {number} byteOffset
* @param {number} value
* @param {*} opts
*/
function setFloat16(dataView, byteOffset, value) {
if (!isDataView(dataView)) throw new TypeError("First argument to setFloat16 function must be a DataView");
for (var _len2 = arguments.length, opts = new Array(_len2 > 3 ? _len2 - 3 : 0), _key2 = 3; _key2 < _len2; _key2++) {
opts[_key2 - 3] = arguments[_key2];
}
dataView.setUint16(byteOffset, roundToFloat16Bits(value), ...opts);
}
exports.Float16Array = Float16Array;
exports.getFloat16 = getFloat16;
exports.hfround = hfround;
exports.setFloat16 = setFloat16;
return exports;
}({}));
================================================
FILE: index.html
================================================
Float Toy
Float Toy
Click on a cell below to toggle bit values, or edit the hex or decimal values directly.
Use this to build intuition for the IEEE floating-point format.
See Wikipedia for details on the half-precision, single-precision and double-precision floating-point formats.
16-bit (half)
32-bit (float)
64-bit (double)