mh-two-thousand-and-two
2024-04-12 7fc6dbf547b8899d949b67cdec36b96a7d1701c7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
'use strict';
 
var GetIntrinsic = require('get-intrinsic');
 
var $parseInt = GetIntrinsic('%parseInt%');
var $abs = GetIntrinsic('%Math.abs%');
var $floor = GetIntrinsic('%Math.floor%');
 
var callBound = require('call-bind/callBound');
 
var $strIndexOf = callBound('String.prototype.indexOf');
var $strSlice = callBound('String.prototype.slice');
 
var fractionToBitString = require('../helpers/fractionToBinaryString');
var intToBinString = require('../helpers/intToBinaryString');
var isNegativeZero = require('./isNegativeZero');
 
var float64bias = 1023;
 
var elevenOnes = '11111111111';
var elevenZeroes = '00000000000';
var fiftyOneZeroes = elevenZeroes + elevenZeroes + elevenZeroes + elevenZeroes + '0000000';
 
// IEEE 754-1985
module.exports = function valueToFloat64Bytes(value, isLittleEndian) {
    var signBit = value < 0 || isNegativeZero(value) ? '1' : '0';
    var exponentBits;
    var significandBits;
 
    if (isNaN(value)) {
        exponentBits = elevenOnes;
        significandBits = '1' + fiftyOneZeroes;
    } else if (!isFinite(value)) {
        exponentBits = elevenOnes;
        significandBits = '0' + fiftyOneZeroes;
    } else if (value === 0) {
        exponentBits = elevenZeroes;
        significandBits = '0' + fiftyOneZeroes;
    } else {
        value = $abs(value); // eslint-disable-line no-param-reassign
 
        // Isolate the integer part (digits before the decimal):
        var integerPart = $floor(value);
 
        var intBinString = intToBinString(integerPart); // bit string for integer part
        var fracBinString = fractionToBitString(value - integerPart); // bit string for fractional part
 
        var numberOfBits;
        // find exponent needed to normalize integer+fractional parts
        if (intBinString) {
            exponentBits = intBinString.length - 1; // move the decimal to the left
        } else {
            var first1 = $strIndexOf(fracBinString, '1');
            if (first1 > -1) {
                numberOfBits = first1 + 1;
            }
            exponentBits = -numberOfBits; // move the decimal to the right
        }
 
        significandBits = intBinString + fracBinString;
        if (exponentBits < 0) {
            // subnormals
            if (exponentBits <= -float64bias) {
                numberOfBits = float64bias - 1; // limit number of removed bits
            }
            significandBits = $strSlice(significandBits, numberOfBits); // remove all leading 0s and the first 1 for normal values; for subnormals, remove up to `float64bias - 1` leading bits
        } else {
            significandBits = $strSlice(significandBits, 1); // remove the leading '1' (implicit/hidden bit)
        }
        exponentBits = $strSlice(elevenZeroes + intToBinString(exponentBits + float64bias), -11); // Convert the exponent to a bit string
 
        significandBits = $strSlice(significandBits + fiftyOneZeroes + '0', 0, 52); // fill in any trailing zeros and ensure we have only 52 fraction bits
    }
 
    var bits = signBit + exponentBits + significandBits;
    var rawBytes = [];
    for (var i = 0; i < 8; i++) {
        var targetIndex = isLittleEndian ? 8 - i - 1 : i;
        rawBytes[targetIndex] = $parseInt($strSlice(bits, i * 8, (i + 1) * 8), 2);
    }
 
    return rawBytes;
};