UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

88 lines (72 loc) 2.51 kB
import { assert } from "../../assert.js"; import { msb_32 } from "../msb_32.js"; // TODO this has some overlap with `frexp` function behavior, perhaps we can generalize /* largely a port from https://github.com/sebbbi/OffsetAllocator */ const MANTISSA_BITS = 3; const MANTISSA_VALUE = 1 << MANTISSA_BITS; const MANTISSA_MASK = MANTISSA_VALUE - 1; /** * Bin sizes follow floating point (exponent + mantissa) distribution (piecewise linear log approx) * This ensures that for each size class, the average overhead percentage stays the same * @param {number} size * @returns {number} uint32 */ export function uintToFloatRoundUp(size) { let exp = 0; let mantissa = 0; if (size < MANTISSA_VALUE) { // Denorm: 0..(MANTISSA_VALUE-1) mantissa = size; } else { // Normalized: Hidden high bit always 1. Not stored. Just like float. const highestSetBit = msb_32(size); const mantissaStartBit = highestSetBit - MANTISSA_BITS; exp = mantissaStartBit + 1; mantissa = (size >>> mantissaStartBit) & MANTISSA_MASK; const lowBitsMask = (1 << mantissaStartBit) - 1; // Round up! if ((size & lowBitsMask) !== 0) { mantissa++; } } return (exp << MANTISSA_BITS) + mantissa; // + allows mantissa->exp overflow for round up } /** * * @param {number} size * @return {number} */ export function uintToFloatRoundDown(size) { let exp = 0; let mantissa = 0; if (size < MANTISSA_VALUE) { // Denorm: 0..(MANTISSA_VALUE-1) mantissa = size; } else { // Normalized: Hidden high bit always 1. Not stored. Just like float. const highestSetBit = msb_32(size); const mantissaStartBit = highestSetBit - MANTISSA_BITS; exp = mantissaStartBit + 1; mantissa = (size >>> mantissaStartBit) & MANTISSA_MASK; } return (exp << MANTISSA_BITS) | mantissa; } /** * * @param {number} floatValue * @return {number} */ export function floatToUint(floatValue) { assert.isNonNegativeInteger(floatValue, 'floatValue'); let exponent = floatValue >>> MANTISSA_BITS; let mantissa = floatValue & MANTISSA_MASK; if (exponent === 0) { // Denorms return mantissa; } else { const x = (mantissa | MANTISSA_VALUE) << (exponent - 1); return x >>> 0; // convert to unsigned in case of sign overflow } }