123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- /**
- * Bitwise and for Bignumbers
- *
- * Special Cases:
- * N & n = N
- * n & 0 = 0
- * n & -1 = n
- * n & n = n
- * I & I = I
- * -I & -I = -I
- * I & -I = 0
- * I & n = n
- * I & -n = I
- * -I & n = 0
- * -I & -n = -I
- *
- * @param {BigNumber} x
- * @param {BigNumber} y
- * @return {BigNumber} Result of `x` & `y`, is fully precise
- * @private
- */
- export function bitAndBigNumber(x, y) {
- if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
- throw new Error('Integers expected in function bitAnd');
- }
- var BigNumber = x.constructor;
- if (x.isNaN() || y.isNaN()) {
- return new BigNumber(NaN);
- }
- if (x.isZero() || y.eq(-1) || x.eq(y)) {
- return x;
- }
- if (y.isZero() || x.eq(-1)) {
- return y;
- }
- if (!x.isFinite() || !y.isFinite()) {
- if (!x.isFinite() && !y.isFinite()) {
- if (x.isNegative() === y.isNegative()) {
- return x;
- }
- return new BigNumber(0);
- }
- if (!x.isFinite()) {
- if (y.isNegative()) {
- return x;
- }
- if (x.isNegative()) {
- return new BigNumber(0);
- }
- return y;
- }
- if (!y.isFinite()) {
- if (x.isNegative()) {
- return y;
- }
- if (y.isNegative()) {
- return new BigNumber(0);
- }
- return x;
- }
- }
- return bitwise(x, y, function (a, b) {
- return a & b;
- });
- }
- /**
- * Bitwise not
- * @param {BigNumber} x
- * @return {BigNumber} Result of ~`x`, fully precise
- *
- */
- export function bitNotBigNumber(x) {
- if (x.isFinite() && !x.isInteger()) {
- throw new Error('Integer expected in function bitNot');
- }
- var BigNumber = x.constructor;
- var prevPrec = BigNumber.precision;
- BigNumber.config({
- precision: 1E9
- });
- var result = x.plus(new BigNumber(1));
- result.s = -result.s || null;
- BigNumber.config({
- precision: prevPrec
- });
- return result;
- }
- /**
- * Bitwise OR for BigNumbers
- *
- * Special Cases:
- * N | n = N
- * n | 0 = n
- * n | -1 = -1
- * n | n = n
- * I | I = I
- * -I | -I = -I
- * I | -n = -1
- * I | -I = -1
- * I | n = I
- * -I | n = -I
- * -I | -n = -n
- *
- * @param {BigNumber} x
- * @param {BigNumber} y
- * @return {BigNumber} Result of `x` | `y`, fully precise
- */
- export function bitOrBigNumber(x, y) {
- if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
- throw new Error('Integers expected in function bitOr');
- }
- var BigNumber = x.constructor;
- if (x.isNaN() || y.isNaN()) {
- return new BigNumber(NaN);
- }
- var negOne = new BigNumber(-1);
- if (x.isZero() || y.eq(negOne) || x.eq(y)) {
- return y;
- }
- if (y.isZero() || x.eq(negOne)) {
- return x;
- }
- if (!x.isFinite() || !y.isFinite()) {
- if (!x.isFinite() && !x.isNegative() && y.isNegative() || x.isNegative() && !y.isNegative() && !y.isFinite()) {
- return negOne;
- }
- if (x.isNegative() && y.isNegative()) {
- return x.isFinite() ? x : y;
- }
- return x.isFinite() ? y : x;
- }
- return bitwise(x, y, function (a, b) {
- return a | b;
- });
- }
- /**
- * Applies bitwise function to numbers
- * @param {BigNumber} x
- * @param {BigNumber} y
- * @param {function (a, b)} func
- * @return {BigNumber}
- */
- export function bitwise(x, y, func) {
- var BigNumber = x.constructor;
- var xBits, yBits;
- var xSign = +(x.s < 0);
- var ySign = +(y.s < 0);
- if (xSign) {
- xBits = decCoefficientToBinaryString(bitNotBigNumber(x));
- for (var i = 0; i < xBits.length; ++i) {
- xBits[i] ^= 1;
- }
- } else {
- xBits = decCoefficientToBinaryString(x);
- }
- if (ySign) {
- yBits = decCoefficientToBinaryString(bitNotBigNumber(y));
- for (var _i = 0; _i < yBits.length; ++_i) {
- yBits[_i] ^= 1;
- }
- } else {
- yBits = decCoefficientToBinaryString(y);
- }
- var minBits, maxBits, minSign;
- if (xBits.length <= yBits.length) {
- minBits = xBits;
- maxBits = yBits;
- minSign = xSign;
- } else {
- minBits = yBits;
- maxBits = xBits;
- minSign = ySign;
- }
- var shortLen = minBits.length;
- var longLen = maxBits.length;
- var expFuncVal = func(xSign, ySign) ^ 1;
- var outVal = new BigNumber(expFuncVal ^ 1);
- var twoPower = new BigNumber(1);
- var two = new BigNumber(2);
- var prevPrec = BigNumber.precision;
- BigNumber.config({
- precision: 1E9
- });
- while (shortLen > 0) {
- if (func(minBits[--shortLen], maxBits[--longLen]) === expFuncVal) {
- outVal = outVal.plus(twoPower);
- }
- twoPower = twoPower.times(two);
- }
- while (longLen > 0) {
- if (func(minSign, maxBits[--longLen]) === expFuncVal) {
- outVal = outVal.plus(twoPower);
- }
- twoPower = twoPower.times(two);
- }
- BigNumber.config({
- precision: prevPrec
- });
- if (expFuncVal === 0) {
- outVal.s = -outVal.s;
- }
- return outVal;
- }
- /* Extracted from decimal.js, and edited to specialize. */
- function decCoefficientToBinaryString(x) {
- // Convert to string
- var a = x.d; // array with digits
- var r = a[0] + '';
- for (var i = 1; i < a.length; ++i) {
- var s = a[i] + '';
- for (var z = 7 - s.length; z--;) {
- s = '0' + s;
- }
- r += s;
- }
- var j = r.length;
- while (r.charAt(j) === '0') {
- j--;
- }
- var xe = x.e;
- var str = r.slice(0, j + 1 || 1);
- var strL = str.length;
- if (xe > 0) {
- if (++xe > strL) {
- // Append zeros.
- xe -= strL;
- while (xe--) {
- str += '0';
- }
- } else if (xe < strL) {
- str = str.slice(0, xe) + '.' + str.slice(xe);
- }
- }
- // Convert from base 10 (decimal) to base 2
- var arr = [0];
- for (var _i2 = 0; _i2 < str.length;) {
- var arrL = arr.length;
- while (arrL--) {
- arr[arrL] *= 10;
- }
- arr[0] += parseInt(str.charAt(_i2++)); // convert to int
- for (var _j = 0; _j < arr.length; ++_j) {
- if (arr[_j] > 1) {
- if (arr[_j + 1] === null || arr[_j + 1] === undefined) {
- arr[_j + 1] = 0;
- }
- arr[_j + 1] += arr[_j] >> 1;
- arr[_j] &= 1;
- }
- }
- }
- return arr.reverse();
- }
- /**
- * Bitwise XOR for BigNumbers
- *
- * Special Cases:
- * N ^ n = N
- * n ^ 0 = n
- * n ^ n = 0
- * n ^ -1 = ~n
- * I ^ n = I
- * I ^ -n = -I
- * I ^ -I = -1
- * -I ^ n = -I
- * -I ^ -n = I
- *
- * @param {BigNumber} x
- * @param {BigNumber} y
- * @return {BigNumber} Result of `x` ^ `y`, fully precise
- *
- */
- export function bitXor(x, y) {
- if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
- throw new Error('Integers expected in function bitXor');
- }
- var BigNumber = x.constructor;
- if (x.isNaN() || y.isNaN()) {
- return new BigNumber(NaN);
- }
- if (x.isZero()) {
- return y;
- }
- if (y.isZero()) {
- return x;
- }
- if (x.eq(y)) {
- return new BigNumber(0);
- }
- var negOne = new BigNumber(-1);
- if (x.eq(negOne)) {
- return bitNotBigNumber(y);
- }
- if (y.eq(negOne)) {
- return bitNotBigNumber(x);
- }
- if (!x.isFinite() || !y.isFinite()) {
- if (!x.isFinite() && !y.isFinite()) {
- return negOne;
- }
- return new BigNumber(x.isNegative() === y.isNegative() ? Infinity : -Infinity);
- }
- return bitwise(x, y, function (a, b) {
- return a ^ b;
- });
- }
- /**
- * Bitwise left shift
- *
- * Special Cases:
- * n << -n = N
- * n << N = N
- * N << n = N
- * n << 0 = n
- * 0 << n = 0
- * I << I = N
- * I << n = I
- * n << I = I
- *
- * @param {BigNumber} x
- * @param {BigNumber} y
- * @return {BigNumber} Result of `x` << `y`
- *
- */
- export function leftShiftBigNumber(x, y) {
- if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
- throw new Error('Integers expected in function leftShift');
- }
- var BigNumber = x.constructor;
- if (x.isNaN() || y.isNaN() || y.isNegative() && !y.isZero()) {
- return new BigNumber(NaN);
- }
- if (x.isZero() || y.isZero()) {
- return x;
- }
- if (!x.isFinite() && !y.isFinite()) {
- return new BigNumber(NaN);
- }
- // Math.pow(2, y) is fully precise for y < 55, and fast
- if (y.lt(55)) {
- return x.times(Math.pow(2, y.toNumber()) + '');
- }
- return x.times(new BigNumber(2).pow(y));
- }
- /*
- * Special Cases:
- * n >> -n = N
- * n >> N = N
- * N >> n = N
- * I >> I = N
- * n >> 0 = n
- * I >> n = I
- * -I >> n = -I
- * -I >> I = -I
- * n >> I = I
- * -n >> I = -1
- * 0 >> n = 0
- *
- * @param {BigNumber} value
- * @param {BigNumber} value
- * @return {BigNumber} Result of `x` >> `y`
- *
- */
- export function rightArithShiftBigNumber(x, y) {
- if (x.isFinite() && !x.isInteger() || y.isFinite() && !y.isInteger()) {
- throw new Error('Integers expected in function rightArithShift');
- }
- var BigNumber = x.constructor;
- if (x.isNaN() || y.isNaN() || y.isNegative() && !y.isZero()) {
- return new BigNumber(NaN);
- }
- if (x.isZero() || y.isZero()) {
- return x;
- }
- if (!y.isFinite()) {
- if (x.isNegative()) {
- return new BigNumber(-1);
- }
- if (!x.isFinite()) {
- return new BigNumber(NaN);
- }
- return new BigNumber(0);
- }
- // Math.pow(2, y) is fully precise for y < 55, and fast
- if (y.lt(55)) {
- return x.div(Math.pow(2, y.toNumber()) + '').floor();
- }
- return x.div(new BigNumber(2).pow(y)).floor();
- }
|