Passed
Push — master ( 6a1a74...309f86 )
by Rafael S.
01:20
created

float.js ➔ toHalf   A

Complexity

Conditions 2
Paths 5

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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