Passed
Push — master ( 20c00a...9a7ed1 )
by Rafael S.
01:38
created

float.js ➔ decodeFloat64   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 19
rs 9.2
1
/*
2
 * float: Functions to work with 16, 32 & 64 bit floats.
3
 * Copyright (c) 2017 Rafael da Silva Rocha.
4
 * https://github.com/rochars/byte-data
5
 */
6
7
function getBinary(bytes, rev=false) {
8
    let binary = "";
9
    let bits;
10
    let i = 0;
11
    let bytesLength = bytes.length;
12
    while(i < bytesLength) {
13
        bits = bytes[i].toString(2);
14
        while (bits.length < 8) {
15
            bits = "0" + bits;
16
        }
17
        if (rev) {
18
            binary = binary + bits;
19
        } else {
20
            binary = bits + binary;
21
        }
22
        i++;
23
    }
24
    return binary;
25
}
26
27
/**
28
 * Turn bytes to a float 16..
29
 * Thanks https://stackoverflow.com/a/8796597
30
 * @param {number} bytes 2 bytes representing a float 16.
31
 */
32
function decodeFloat16 (bytes) {
33
    let binary = parseInt(getBinary(bytes, true), 2);
34
    let exponent = (binary & 0x7C00) >> 10;
35
    let fraction = binary & 0x03FF;
36
    let floatValue;
37
    if (exponent) {
38
        floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
39
    } else {
40
        floatValue = 6.103515625e-5 * (fraction / 0x400);
41
    }
42
    return  floatValue * (binary >> 15 ? -1 : 1);
43
}
44
45
/**
46
 * Turn an array of bytes into a float 64.
47
 * Thanks https://gist.github.com/kg/2192799
48
 * @param {!Array<number>} bytes 8 bytes representing a float 64.
49
 */
50
function decodeFloat64(bytes) {
51
    if (bytes.toString() == "0,0,0,0,0,0,0,0") {
52
        return 0;
53
    }
54
    let binary = getBinary(bytes);
55
    let significandBin = "1" + binary.substr(1 + 11, 52);
56
    let val = 1;
57
    let significand = 0;
58
    let i = 0;
59
    while (i < significandBin.length) {
60
        significand += val * parseInt(significandBin.charAt(i), 10);
61
        val = val / 2;
62
        i++;
63
    }
64
    let sign = (binary.charAt(0) == "1") ? -1 : 1;
65
    let doubleValue = sign * significand *
66
        Math.pow(2, parseInt(binary.substr(1, 11), 2) - 1023);
67
    return doubleValue;
68
}
69
70
/**
71
 * Unpack a 64 bit float into two words.
72
 * Thanks https://stackoverflow.com/a/16043259
73
 * @param {number} value A float64 number.
74
 */
75
function toFloat64(value) {
76
    if (value == 0) {
77
        return [0, 0];
78
    }
79
    let hiWord = 0;
80
    let loWord = 0;
81
    if (value <= 0.0) {
82
        hiWord = 0x80000000;
83
        value = -value;
84
    }
85
    let exponent = Math.floor(
86
        Math.log(value) / Math.log(2));
87
    let significand = Math.floor(
88
        (value / Math.pow(2, exponent)) * Math.pow(2, 52));
89
    loWord = significand & 0xFFFFFFFF;
90
    significand /= Math.pow(2, 32);
91
    exponent += 1023;
92
    hiWord = hiWord | (exponent << 20);
93
    hiWord = hiWord | (significand & ~(-1 << 20));
94
    return [hiWord, loWord];
95
}
96
97
let floatView = new Float32Array(1);
98
let int32View = new Int32Array(floatView.buffer);
99
100
/*!
101
 * to-half: int bits of half-precision floating point values
102
 * Based on:
103
 * https://mail.mozilla.org/pipermail/es-discuss/2017-April/047994.html
104
 * https://github.com/rochars/byte-data
105
 */
106
function toHalf(val) {
107
    floatView[0] = val;
108
    let x = int32View[0];
109
    let bits = (x >> 16) & 0x8000;
110
    let m = (x >> 12) & 0x07ff;
111
    let e = (x >> 23) & 0xff;
112
    if (e < 103) {
113
        return bits;
114
    }
115
    bits |= ((e - 112) << 10) | (m >> 1);
116
    bits += m & 1;
117
    return bits;
118
}
119
120
module.exports.getBinary = getBinary;
121
module.exports.decodeFloat16 = decodeFloat16;
122
module.exports.decodeFloat64 = decodeFloat64;
123
module.exports.toFloat64 = toFloat64;
124
module.exports.toHalf = toHalf;
125