Skip to content

Instantly share code, notes, and snippets.

@SPY
Last active April 20, 2021 02:25
Show Gist options
  • Save SPY/505ab63b53d95eb72fe74c88fe8739e4 to your computer and use it in GitHub Desktop.
Save SPY/505ab63b53d95eb72fe74c88fe8739e4 to your computer and use it in GitHub Desktop.
JS parser for Float Hex notation
function floatToWord(f) {
let b = new ArrayBuffer(4)
let iView = new Uint32Array(b)
let fView = new Float32Array(b)
fView[0] = f
return iView[0]
}
function wordToFloat(w) {
let b = new ArrayBuffer(4)
let iView = new Uint32Array(b)
let fView = new Float32Array(b)
iView[0] = w
return fView[0]
}
function readHexFloat(str) {
var [_, sign, int, _, frac, _, expStr] = /^([+-]?)0x([0-9a-f]*)(\.([0-9a-f]*))?([pP]([+-]?\d*))?$/.exec(str.toLowerCase())
let exp = parseInt(expStr || '0', 10)
int = int.replace(/^0*/, '') || '0'
frac = (frac || '').replace(/0*$/, '') || '0'
let w = sign === '-' ? 0x80000000 : 0
if (parseInt(int, 16)) {
frac = int + frac
exp += int.length * 4
}
if (parseInt(frac, 16) === 0) {
return wordToFloat(w)
}
let hexFracWithoutLeadingZeros = frac.replace(/^0*/, '')
exp -= (frac.length - hexFracWithoutLeadingZeros.length) * 4
let binFrac = parseInt(frac, 16).toString(2)
exp -= hexFracWithoutLeadingZeros.length * 4 - binFrac.length + 1
binFrac = binFrac.replace(/0*$/, '')
const budget = Math.min(24, 150 + exp)
if (binFrac.length > budget) {
let roundedFrac = binFrac.slice(0, budget)
let rest = binFrac.slice(budget)
if (rest[0] === '1' && (rest.length > 1 || roundedFrac[roundedFrac.length - 1] === '1')) {
if (roundedFrac.length === roundedFrac.replace('0', '').length) {
exp++
binFrac = '1'
}
else {
binFrac = (parseInt(roundedFrac, 2) + 1).toString(2)
}
}
else {
binFrac = roundedFrac
}
}
if (exp < -150 || exp > 127) {
throw Error('Constant out of range: ' + exp)
}
if (exp >= -126) {
w = w | ((exp + 127) << 23) | (parseInt(binFrac.slice(1) || '0', 2) << (24 - binFrac.length))
}
else {
const shift = 150 - binFrac.length - Math.abs(exp)
if (shift < 0) {
return wordToFloat(w)
}
w = w | (parseInt(binFrac, 2) << (150 - binFrac.length - Math.abs(exp)))
}
return wordToFloat(w)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment