-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfull-precision-with-bigints.mjs
50 lines (45 loc) · 1.62 KB
/
full-precision-with-bigints.mjs
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
import { floatFromParts, partsFromFloat } from './float-tools.mjs';
export function floatToBigInt(double) {
if (!Number.isFinite(double)) throw new Error('todo');
let { sign, exponent, significand } = partsFromFloat(double);
let magnitude;
if (exponent === 0) {
magnitude = BigInt(significand) * 2n; // hm.
} else {
significand = 2n ** 52n + BigInt(significand);
magnitude = 2n ** (BigInt(exponent)) * significand;
}
return sign ? -magnitude : magnitude;
}
let biggest = floatToBigInt(1.79769313486231570815e+308);
export function bigIntToFloat(bigint) {
let sign = bigint < 0 ? 1 : 0;
let magnitude = bigint < 0 ? -bigint : bigint;
let binary = magnitude.toString(2);
if (binary === 0) {
return sign ? -0 : 0;
}
if (binary.length <= 53) {
// subnormal
// assert(binary[binary.length - 1] === '0')
let significand = parseInt(binary, 2) / 2;
let exponent = 0;
return floatFromParts({ sign, exponent, significand });
}
let significandString = binary.slice(1, 53);
let significand = parseInt(significandString, 2);
let exponent = binary.length - 53;
// round up if we are at least half way. if up is towards-even we always round up; otherwise we round up iff it is above the halfway point, i.e. there is a non-zero bit after the first
let roundUp = binary[53] === '1' && (binary[52] === '1' || binary.slice(54).includes('1'));
if (roundUp) {
significand += 1;
if (significand === 2 ** 52) {
significand = 0;
exponent += 1;
}
}
if (exponent > 2046) {
return sign ? -Infinity : Infinity;
}
return floatFromParts({ sign, exponent, significand });
}