UNPKG

2.9 kBJavaScriptView Raw
1'use strict'
2const bitNot = require('./bitNot')
3
4/**
5 * Applies bitwise function to numbers
6 * @param {BigNumber} x
7 * @param {BigNumber} y
8 * @param {function (a, b)} func
9 * @return {BigNumber}
10 */
11module.exports = function bitwise (x, y, func) {
12 const BigNumber = x.constructor
13
14 let xBits, yBits
15 const xSign = +(x.s < 0)
16 const ySign = +(y.s < 0)
17 if (xSign) {
18 xBits = decCoefficientToBinaryString(bitNot(x))
19 for (let i = 0; i < xBits.length; ++i) {
20 xBits[i] ^= 1
21 }
22 } else {
23 xBits = decCoefficientToBinaryString(x)
24 }
25 if (ySign) {
26 yBits = decCoefficientToBinaryString(bitNot(y))
27 for (let i = 0; i < yBits.length; ++i) {
28 yBits[i] ^= 1
29 }
30 } else {
31 yBits = decCoefficientToBinaryString(y)
32 }
33
34 let minBits, maxBits, minSign
35 if (xBits.length <= yBits.length) {
36 minBits = xBits
37 maxBits = yBits
38 minSign = xSign
39 } else {
40 minBits = yBits
41 maxBits = xBits
42 minSign = ySign
43 }
44
45 let shortLen = minBits.length
46 let longLen = maxBits.length
47 const expFuncVal = func(xSign, ySign) ^ 1
48 let outVal = new BigNumber(expFuncVal ^ 1)
49 let twoPower = new BigNumber(1)
50 const two = new BigNumber(2)
51
52 const prevPrec = BigNumber.precision
53 BigNumber.config({ precision: 1E9 })
54
55 while (shortLen > 0) {
56 if (func(minBits[--shortLen], maxBits[--longLen]) === expFuncVal) {
57 outVal = outVal.plus(twoPower)
58 }
59 twoPower = twoPower.times(two)
60 }
61 while (longLen > 0) {
62 if (func(minSign, maxBits[--longLen]) === expFuncVal) {
63 outVal = outVal.plus(twoPower)
64 }
65 twoPower = twoPower.times(two)
66 }
67
68 BigNumber.config({ precision: prevPrec })
69
70 if (expFuncVal === 0) {
71 outVal.s = -outVal.s
72 }
73 return outVal
74}
75
76/* Extracted from decimal.js, and edited to specialize. */
77function decCoefficientToBinaryString (x) {
78 // Convert to string
79 const a = x.d // array with digits
80 let r = a[0] + ''
81
82 for (let i = 1; i < a.length; ++i) {
83 let s = a[i] + ''
84 for (let z = 7 - s.length; z--;) {
85 s = '0' + s
86 }
87
88 r += s
89 }
90
91 let j = r.length
92 while (r.charAt(j) === '0') {
93 j--
94 }
95
96 let xe = x.e
97 let str = r.slice(0, j + 1 || 1)
98 const strL = str.length
99 if (xe > 0) {
100 if (++xe > strL) {
101 // Append zeros.
102 xe -= strL
103 while (xe--) {
104 str += '0'
105 }
106 } else if (xe < strL) {
107 str = str.slice(0, xe) + '.' + str.slice(xe)
108 }
109 }
110
111 // Convert from base 10 (decimal) to base 2
112 const arr = [0]
113 for (let i = 0; i < str.length;) {
114 let arrL = arr.length
115 while (arrL--) {
116 arr[arrL] *= 10
117 }
118
119 arr[0] += parseInt(str.charAt(i++)) // convert to int
120 for (let j = 0; j < arr.length; ++j) {
121 if (arr[j] > 1) {
122 if (arr[j + 1] === null || arr[j + 1] === undefined) {
123 arr[j + 1] = 0
124 }
125
126 arr[j + 1] += arr[j] >> 1
127 arr[j] &= 1
128 }
129 }
130 }
131
132 return arr.reverse()
133}