UNPKG

9.13 kBJavaScriptView Raw
1/**
2 * Bitwise and for Bignumbers
3 *
4 * Special Cases:
5 * N & n = N
6 * n & 0 = 0
7 * n & -1 = n
8 * n & n = n
9 * I & I = I
10 * -I & -I = -I
11 * I & -I = 0
12 * I & n = n
13 * I & -n = I
14 * -I & n = 0
15 * -I & -n = -I
16 *
17 * @param {BigNumber} x
18 * @param {BigNumber} y
19 * @return {BigNumber} Result of `x` & `y`, is fully precise
20 * @private
21 */
22export function bitAndBigNumber(x, y) {
23 if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
24 throw new Error('Integers expected in function bitAnd');
25 }
26
27 var BigNumber = x.constructor;
28
29 if (x.isNaN() || y.isNaN()) {
30 return new BigNumber(NaN);
31 }
32
33 if (x.isZero() || y.eq(-1) || x.eq(y)) {
34 return x;
35 }
36
37 if (y.isZero() || x.eq(-1)) {
38 return y;
39 }
40
41 if (!x.isFinite() || !y.isFinite()) {
42 if (!x.isFinite() && !y.isFinite()) {
43 if (x.isNegative() === y.isNegative()) {
44 return x;
45 }
46
47 return new BigNumber(0);
48 }
49
50 if (!x.isFinite()) {
51 if (y.isNegative()) {
52 return x;
53 }
54
55 if (x.isNegative()) {
56 return new BigNumber(0);
57 }
58
59 return y;
60 }
61
62 if (!y.isFinite()) {
63 if (x.isNegative()) {
64 return y;
65 }
66
67 if (y.isNegative()) {
68 return new BigNumber(0);
69 }
70
71 return x;
72 }
73 }
74
75 return bitwise(x, y, function (a, b) {
76 return a & b;
77 });
78}
79/**
80 * Bitwise not
81 * @param {BigNumber} x
82 * @return {BigNumber} Result of ~`x`, fully precise
83 *
84 */
85
86export function bitNotBigNumber(x) {
87 if (x.isFinite() && !x.isInteger()) {
88 throw new Error('Integer expected in function bitNot');
89 }
90
91 var BigNumber = x.constructor;
92 var prevPrec = BigNumber.precision;
93 BigNumber.config({
94 precision: 1E9
95 });
96 var result = x.plus(new BigNumber(1));
97 result.s = -result.s || null;
98 BigNumber.config({
99 precision: prevPrec
100 });
101 return result;
102}
103/**
104 * Bitwise OR for BigNumbers
105 *
106 * Special Cases:
107 * N | n = N
108 * n | 0 = n
109 * n | -1 = -1
110 * n | n = n
111 * I | I = I
112 * -I | -I = -I
113 * I | -n = -1
114 * I | -I = -1
115 * I | n = I
116 * -I | n = -I
117 * -I | -n = -n
118 *
119 * @param {BigNumber} x
120 * @param {BigNumber} y
121 * @return {BigNumber} Result of `x` | `y`, fully precise
122 */
123
124export function bitOrBigNumber(x, y) {
125 if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
126 throw new Error('Integers expected in function bitOr');
127 }
128
129 var BigNumber = x.constructor;
130
131 if (x.isNaN() || y.isNaN()) {
132 return new BigNumber(NaN);
133 }
134
135 var negOne = new BigNumber(-1);
136
137 if (x.isZero() || y.eq(negOne) || x.eq(y)) {
138 return y;
139 }
140
141 if (y.isZero() || x.eq(negOne)) {
142 return x;
143 }
144
145 if (!x.isFinite() || !y.isFinite()) {
146 if (!x.isFinite() && !x.isNegative() && y.isNegative() || x.isNegative() && !y.isNegative() && !y.isFinite()) {
147 return negOne;
148 }
149
150 if (x.isNegative() && y.isNegative()) {
151 return x.isFinite() ? x : y;
152 }
153
154 return x.isFinite() ? y : x;
155 }
156
157 return bitwise(x, y, function (a, b) {
158 return a | b;
159 });
160}
161/**
162 * Applies bitwise function to numbers
163 * @param {BigNumber} x
164 * @param {BigNumber} y
165 * @param {function (a, b)} func
166 * @return {BigNumber}
167 */
168
169export function bitwise(x, y, func) {
170 var BigNumber = x.constructor;
171 var xBits, yBits;
172 var xSign = +(x.s < 0);
173 var ySign = +(y.s < 0);
174
175 if (xSign) {
176 xBits = decCoefficientToBinaryString(bitNotBigNumber(x));
177
178 for (var i = 0; i < xBits.length; ++i) {
179 xBits[i] ^= 1;
180 }
181 } else {
182 xBits = decCoefficientToBinaryString(x);
183 }
184
185 if (ySign) {
186 yBits = decCoefficientToBinaryString(bitNotBigNumber(y));
187
188 for (var _i = 0; _i < yBits.length; ++_i) {
189 yBits[_i] ^= 1;
190 }
191 } else {
192 yBits = decCoefficientToBinaryString(y);
193 }
194
195 var minBits, maxBits, minSign;
196
197 if (xBits.length <= yBits.length) {
198 minBits = xBits;
199 maxBits = yBits;
200 minSign = xSign;
201 } else {
202 minBits = yBits;
203 maxBits = xBits;
204 minSign = ySign;
205 }
206
207 var shortLen = minBits.length;
208 var longLen = maxBits.length;
209 var expFuncVal = func(xSign, ySign) ^ 1;
210 var outVal = new BigNumber(expFuncVal ^ 1);
211 var twoPower = new BigNumber(1);
212 var two = new BigNumber(2);
213 var prevPrec = BigNumber.precision;
214 BigNumber.config({
215 precision: 1E9
216 });
217
218 while (shortLen > 0) {
219 if (func(minBits[--shortLen], maxBits[--longLen]) === expFuncVal) {
220 outVal = outVal.plus(twoPower);
221 }
222
223 twoPower = twoPower.times(two);
224 }
225
226 while (longLen > 0) {
227 if (func(minSign, maxBits[--longLen]) === expFuncVal) {
228 outVal = outVal.plus(twoPower);
229 }
230
231 twoPower = twoPower.times(two);
232 }
233
234 BigNumber.config({
235 precision: prevPrec
236 });
237
238 if (expFuncVal === 0) {
239 outVal.s = -outVal.s;
240 }
241
242 return outVal;
243}
244/* Extracted from decimal.js, and edited to specialize. */
245
246function decCoefficientToBinaryString(x) {
247 // Convert to string
248 var a = x.d; // array with digits
249
250 var r = a[0] + '';
251
252 for (var i = 1; i < a.length; ++i) {
253 var s = a[i] + '';
254
255 for (var z = 7 - s.length; z--;) {
256 s = '0' + s;
257 }
258
259 r += s;
260 }
261
262 var j = r.length;
263
264 while (r.charAt(j) === '0') {
265 j--;
266 }
267
268 var xe = x.e;
269 var str = r.slice(0, j + 1 || 1);
270 var strL = str.length;
271
272 if (xe > 0) {
273 if (++xe > strL) {
274 // Append zeros.
275 xe -= strL;
276
277 while (xe--) {
278 str += '0';
279 }
280 } else if (xe < strL) {
281 str = str.slice(0, xe) + '.' + str.slice(xe);
282 }
283 } // Convert from base 10 (decimal) to base 2
284
285
286 var arr = [0];
287
288 for (var _i2 = 0; _i2 < str.length;) {
289 var arrL = arr.length;
290
291 while (arrL--) {
292 arr[arrL] *= 10;
293 }
294
295 arr[0] += parseInt(str.charAt(_i2++)); // convert to int
296
297 for (var _j = 0; _j < arr.length; ++_j) {
298 if (arr[_j] > 1) {
299 if (arr[_j + 1] === null || arr[_j + 1] === undefined) {
300 arr[_j + 1] = 0;
301 }
302
303 arr[_j + 1] += arr[_j] >> 1;
304 arr[_j] &= 1;
305 }
306 }
307 }
308
309 return arr.reverse();
310}
311/**
312 * Bitwise XOR for BigNumbers
313 *
314 * Special Cases:
315 * N ^ n = N
316 * n ^ 0 = n
317 * n ^ n = 0
318 * n ^ -1 = ~n
319 * I ^ n = I
320 * I ^ -n = -I
321 * I ^ -I = -1
322 * -I ^ n = -I
323 * -I ^ -n = I
324 *
325 * @param {BigNumber} x
326 * @param {BigNumber} y
327 * @return {BigNumber} Result of `x` ^ `y`, fully precise
328 *
329 */
330
331
332export function bitXor(x, y) {
333 if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
334 throw new Error('Integers expected in function bitXor');
335 }
336
337 var BigNumber = x.constructor;
338
339 if (x.isNaN() || y.isNaN()) {
340 return new BigNumber(NaN);
341 }
342
343 if (x.isZero()) {
344 return y;
345 }
346
347 if (y.isZero()) {
348 return x;
349 }
350
351 if (x.eq(y)) {
352 return new BigNumber(0);
353 }
354
355 var negOne = new BigNumber(-1);
356
357 if (x.eq(negOne)) {
358 return bitNotBigNumber(y);
359 }
360
361 if (y.eq(negOne)) {
362 return bitNotBigNumber(x);
363 }
364
365 if (!x.isFinite() || !y.isFinite()) {
366 if (!x.isFinite() && !y.isFinite()) {
367 return negOne;
368 }
369
370 return new BigNumber(x.isNegative() === y.isNegative() ? Infinity : -Infinity);
371 }
372
373 return bitwise(x, y, function (a, b) {
374 return a ^ b;
375 });
376}
377/**
378 * Bitwise left shift
379 *
380 * Special Cases:
381 * n << -n = N
382 * n << N = N
383 * N << n = N
384 * n << 0 = n
385 * 0 << n = 0
386 * I << I = N
387 * I << n = I
388 * n << I = I
389 *
390 * @param {BigNumber} x
391 * @param {BigNumber} y
392 * @return {BigNumber} Result of `x` << `y`
393 *
394 */
395
396export function leftShiftBigNumber(x, y) {
397 if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
398 throw new Error('Integers expected in function leftShift');
399 }
400
401 var BigNumber = x.constructor;
402
403 if (x.isNaN() || y.isNaN() || y.isNegative() && !y.isZero()) {
404 return new BigNumber(NaN);
405 }
406
407 if (x.isZero() || y.isZero()) {
408 return x;
409 }
410
411 if (!x.isFinite() && !y.isFinite()) {
412 return new BigNumber(NaN);
413 } // Math.pow(2, y) is fully precise for y < 55, and fast
414
415
416 if (y.lt(55)) {
417 return x.times(Math.pow(2, y.toNumber()) + '');
418 }
419
420 return x.times(new BigNumber(2).pow(y));
421}
422/*
423 * Special Cases:
424 * n >> -n = N
425 * n >> N = N
426 * N >> n = N
427 * I >> I = N
428 * n >> 0 = n
429 * I >> n = I
430 * -I >> n = -I
431 * -I >> I = -I
432 * n >> I = I
433 * -n >> I = -1
434 * 0 >> n = 0
435 *
436 * @param {BigNumber} value
437 * @param {BigNumber} value
438 * @return {BigNumber} Result of `x` >> `y`
439 *
440 */
441
442export function rightArithShiftBigNumber(x, y) {
443 if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
444 throw new Error('Integers expected in function rightArithShift');
445 }
446
447 var BigNumber = x.constructor;
448
449 if (x.isNaN() || y.isNaN() || y.isNegative() && !y.isZero()) {
450 return new BigNumber(NaN);
451 }
452
453 if (x.isZero() || y.isZero()) {
454 return x;
455 }
456
457 if (!y.isFinite()) {
458 if (x.isNegative()) {
459 return new BigNumber(-1);
460 }
461
462 if (!x.isFinite()) {
463 return new BigNumber(NaN);
464 }
465
466 return new BigNumber(0);
467 } // Math.pow(2, y) is fully precise for y < 55, and fast
468
469
470 if (y.lt(55)) {
471 return x.div(Math.pow(2, y.toNumber()) + '').floor();
472 }
473
474 return x.div(new BigNumber(2).pow(y)).floor();
475}
\No newline at end of file