This repository was archived by the owner on Jun 11, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbinops.js
More file actions
142 lines (117 loc) · 4.14 KB
/
binops.js
File metadata and controls
142 lines (117 loc) · 4.14 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
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
var BinOps = (function () {
"use strict";
// BinOps uses chunks of 31 bits to safely work in the domain of
// signed 32 bit integers.
// Since we want to represent numbers on 53 bits, we have to
// split them into 2 chunks:
// bit 0 to 30 -> 31 bits
// bit 31 to 52 -> 22 bits
// We don’t use more than 53 bits because, with larger numbers,
// JavaScript starts storing them as IEEE-754 floats,
// and bitwise logic cannot apply anymore.
const TWO_POWER_22 = 2 ** 22;
const TWO_POWER_31 = 2 ** 31;
const TWO_POWER_53 = 2 ** 53;
const MASK_31 = TWO_POWER_31 - 1;
const MASK_22 = TWO_POWER_22 - 1;
const CONDITION_UNSIGNED_53_BITS = Symbol();
const CONDITION_SHIFT_OPERAND = Symbol();
var checkArg = function (arg, condition) {
switch (condition) {
case CONDITION_UNSIGNED_53_BITS:
if (!Number.isInteger(arg) || arg < 0 || !Number.isSafeInteger(arg)) {
throw new Error("argument must be an unsigned 53 bits integer");
}
break;
case CONDITION_SHIFT_OPERAND:
if (!Number.isInteger(arg) || arg < 0 || arg >= 53) {
throw new Error("argument must be an integer >= 0 and < 53");
}
break;
default:
console.warn("unimplemented condition");
break;
}
};
return {
not: function (a) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
var lowerChunk = a % TWO_POWER_31;
var upperChunk = Math.floor(a / TWO_POWER_31);
var maskedLowerChunk = (~lowerChunk) & MASK_31;
var maskedUpperChunk = (~upperChunk) & MASK_22;
return maskedLowerChunk + TWO_POWER_31 * maskedUpperChunk;
},
and: function (a, b) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
checkArg(b, CONDITION_UNSIGNED_53_BITS);
var lowerA = a % TWO_POWER_31;
var upperA = Math.floor(a / TWO_POWER_31);
var lowerB = b % TWO_POWER_31;
var upperB = Math.floor(b / TWO_POWER_31);
var lowerResult = lowerA & lowerB & MASK_31;
var upperResult = upperA & upperB & MASK_22;
return lowerResult + TWO_POWER_31 * upperResult;
},
or: function (a, b) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
checkArg(b, CONDITION_UNSIGNED_53_BITS);
var lowerA = a % TWO_POWER_31;
var upperA = Math.floor(a / TWO_POWER_31);
var lowerB = b % TWO_POWER_31;
var upperB = Math.floor(b / TWO_POWER_31);
var lowerResult = (lowerA | lowerB) & MASK_31;
var upperResult = (upperA | upperB) & MASK_22;
return lowerResult + TWO_POWER_31 * upperResult;
},
xor: function (a, b) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
checkArg(b, CONDITION_UNSIGNED_53_BITS);
var lowerA = a % TWO_POWER_31;
var upperA = Math.floor(a / TWO_POWER_31);
var lowerB = b % TWO_POWER_31;
var upperB = Math.floor(b / TWO_POWER_31);
var lowerResult = (lowerA ^ lowerB) & MASK_31;
var upperResult = (upperA ^ upperB) & MASK_22;
return lowerResult + TWO_POWER_31 * upperResult;
},
lshift: function (a, n) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
checkArg(n, CONDITION_SHIFT_OPERAND);
var lower = a % TWO_POWER_31;
var upper = Math.floor(a / TWO_POWER_31);
if (n >= 31) {
upper = (lower & (2 ** (53-n) - 1)) << (n-31);
lower = 0;
}
else if (n >= 22) {
upper = (lower >> (31-n)) & MASK_22;
lower = (lower & (2**(31-n) - 1)) << n;
}
else {
upper = ((upper << n) | (lower >> (31-n)) ) & MASK_22;
lower = (lower << n) & MASK_31;
}
return lower + TWO_POWER_31 * upper;
},
urshift: function (a, n) {
checkArg(a, CONDITION_UNSIGNED_53_BITS);
checkArg(n, CONDITION_SHIFT_OPERAND);
var lower = a % TWO_POWER_31;
var upper = Math.floor(a / TWO_POWER_31);
if (n >= 31) {
lower = upper >> (n-31);
upper = 0;
}
else if (n >= 22) {
lower = (lower >> n) | (upper << (31-n));
upper = 0;
}
else {
lower = (lower >> n) | ((upper & (2**n - 1)) << (31-n));
upper = upper >> n;
}
return lower + TWO_POWER_31 * upper;
}
};
}());