import Binary from './Binary' ; type BinaryLike = Binary | Uint8Array | Uint32Array ; const toBinary = ( binaryLike ) : Binary => { if ( binaryLike instanceof Binary ) { return binaryLike ; } if ( binaryLike instanceof Uint32Array ) { return Binary . fromUint32Array ( binaryLike ) ; } if ( binaryLike instanceof Uint8Array ) { return Binary . fromUint8Array ( binaryLike ) ; } throw new Error ( `Unsupported conversion to Binary for type: "${ typeof binaryLike }"` ) ; } ; export interface FloatConversionOptions { sizeOfExp : number ; sizeOfMantissa : number ; bias : number ; } export interface FloatToBinaryOptions extends FloatConversionOptions { value : number ; } export const floatToBinary = ( options ) : Binary => { let { value } = options ; const { sizeOfExp , sizeOfMantissa , bias , } = options ; const size = 1 + sizeOfExp + sizeOfMantissa ; const signBit = value > 0 ? 0 : 1 ; const binary = new Binary ( size ) ; let expValue = Math . floor ( Math . log ( value ) / Math . log ( 2 ) ) + bias ; value = Math . abs ( value ) ; let dm = value % 1 ; let dc = value - dm ; const log2 = Math . floor ( Math . log ( value ) / Math . log ( 2 ) ) ; const bits = new Array ( log2 <= 0 ? 0 : log2 + 1 ) ; for ( let i = bits . length - 1 ; i >= 0 ; i -- ) { bits [ i ] = dc % 2 ; dc = ( dc / 2 ) | 0 ; } while ( dm > 0 ) { const v = dm * 2 ; dm = v % 1 ; bits . push ( v - dm ) ; } while ( bits [ 0 ] === 0 ) { bits . shift ( ) ; } bits . slice ( 1 , 1 + sizeOfMantissa ) . forEach ( ( bit , i ) => { binary . setBit ( sizeOfMantissa - 1 - i , bit ) ; } ) ; const expUpper = sizeOfMantissa + sizeOfExp ; for ( let i = sizeOfMantissa ; i < expUpper && expValue > 0 ; i ++ ) { binary . setBit ( i , expValue % 2 ) ; expValue = ( expValue / 2 ) | 0 ; } binary . setBit ( size - 1 , signBit ) ; return binary ; } ; export interface FloatFromBinaryOptions extends FloatConversionOptions { binary : Binary ; } export const floatFromBinary = ( options ) : number => { const { binary , sizeOfExp , sizeOfMantissa , bias , } = options ; const exp = binary . getRange ( sizeOfMantissa , sizeOfMantissa + sizeOfExp - 1 ) - bias ; let value = 1 ; for ( let i = sizeOfMantissa - 1 , j = - 1 ; i >= 0 ; i -- , j -- ) { value += binary . getBit ( i ) * Math . pow ( 2 , j ) ; } value *= Math . pow ( 2 , exp ) ; if ( binary . getBit ( binary . size - 1 ) ) { value *= - 1 ; } return value ; } ; export const SINGLE_MANTISSA = 23 ; export const SINGLE_EXPONENT = 8 ; export const SINGLE_BIAS = 127 ; export const DOUBLE_MANTISSA = 52 ; export const DOUBLE_EXPONENT = 11 ; export const DOUBLE_BIAS = 1023 ; export const singleFromBinary = ( binaryLike ) : number => { const binary = toBinary ( binaryLike ) ; return floatFromBinary ( { binary , sizeOfExp : SINGLE_EXPONENT , sizeOfMantissa : SINGLE_MANTISSA , bias : SINGLE_BIAS , } ) ; } ; export const doubleFromBinary = ( binaryLike ) : number => { const binary = toBinary ( binaryLike ) ; return floatFromBinary ( { binary , sizeOfExp : DOUBLE_EXPONENT , sizeOfMantissa : DOUBLE_MANTISSA , bias : DOUBLE_BIAS , } ) ; } ; export const singleToBinary = ( single ) : Binary => { return floatToBinary ( { value : single , sizeOfExp : SINGLE_EXPONENT , sizeOfMantissa : SINGLE_MANTISSA , bias : SINGLE_BIAS , } ) ; } ; export const doubleToBinary = ( double ) : Binary => { return floatToBinary ( { value : double , sizeOfExp : DOUBLE_EXPONENT , sizeOfMantissa : DOUBLE_MANTISSA , bias : DOUBLE_BIAS , } ) ; } ;