bitwise.js 8.8 KB

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