forked from rocicorp/mono
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfloat-to-ordered-string.ts
More file actions
48 lines (38 loc) · 1.37 KB
/
float-to-ordered-string.ts
File metadata and controls
48 lines (38 loc) · 1.37 KB
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
import {assert} from './asserts.js';
import {parseBigInt} from './parse-big-int.js';
const view = new DataView(new ArrayBuffer(8));
export function encodeFloat64AsString(n: number) {
view.setFloat64(0, n);
const high = view.getUint32(0);
const low = view.getUint32(4);
// The sign bit is 1 for negative numbers
// We flip the sign bit so that positive numbers are ordered before negative numbers
// If negative we flip all the bits so that larger absolute numbers are treated smaller
if (n < 0 || Object.is(n, -0)) {
view.setUint32(0, high ^ 0xffffffff);
view.setUint32(4, low ^ 0xffffffff);
} else {
// we only flip the sign
view.setUint32(0, high ^ (1 << 31));
}
const bigint = view.getBigUint64(0);
return bigint.toString(36).padStart(13, '0');
}
export function decodeFloat64AsString(s: string): number {
assert(s.length === 13, `Invalid encoded float64: ${s}`);
const bigint = parseBigInt(s, 36);
view.setBigUint64(0, bigint);
const high = view.getUint32(0);
const low = view.getUint32(4);
const sign = high >> 31;
// Positive
if (sign) {
// we only flip the sign
view.setUint32(0, high ^ (1 << 31));
} else {
// If negative we flipped all the bits so that larger absolute numbers are treated smaller
view.setUint32(0, high ^ 0xffffffff);
view.setUint32(4, low ^ 0xffffffff);
}
return view.getFloat64(0);
}