bitwise.js (9129B)
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 */ 22 export 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 86 export 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 124 export 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 169 export 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 246 function 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 332 export 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 396 export 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 442 export 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 }