1 | 1 | 'use strict'; |
2 | | |
3 | | // ---------------------------------------------------------------------- |
4 | | // ----- main exported object |
5 | | // includes: |
6 | | // 1. unit conversions |
7 | | // 2. arithmetic functions |
8 | | // 3. logical operators |
9 | | // 4. helper methods |
10 | | // ---------------------------------------------------------------------- |
11 | | |
12 | 1 | var binary = module.exports = {}; |
13 | | |
14 | | |
15 | | // ----- unit conversion |
16 | | // --------------------------------------- |
17 | 1 | binary.toInt = function(str) { |
18 | 10 | return parseInt(str, 2); |
19 | | }; |
20 | | |
21 | 1 | binary.toHex = function(str) { |
22 | 2 | return parseInt(str, 2).toString(16); |
23 | | }; |
24 | | |
25 | | // binary.toBase64 = function(str) { |
26 | | // str = parseInt(str, 2).toString(); |
27 | | // var buf = new Buffer(str); |
28 | | // return buf.toString('base64'); |
29 | | // }; |
30 | | |
31 | | // @param n {Number | String | Buffer} input |
32 | | // @param len? {Number} optional bitlength restriction |
33 | | // @return {String} 8bit binary conversion |
34 | 1 | binary.toBinary = function(n, len) { |
35 | | |
36 | 8 | var type = Object.prototype.toString.call(n); |
37 | | |
38 | 8 | if (type === '[object Number]') { |
39 | | |
40 | 4 | if (len) { |
41 | 2 | return binary.pad(n.toString(2), len); |
42 | | } |
43 | | else { |
44 | 2 | return n.toString(2); |
45 | | } |
46 | | |
47 | | } |
48 | | |
49 | 4 | var output = ''; |
50 | | |
51 | 4 | for (var i = 0; i < n.length; i++) { |
52 | | |
53 | 22 | var cur = typeof n[i] === 'number' ? |
54 | | binary.pad(n[i].toString(2), 8) // buffers |
55 | | : binary.pad(n.charCodeAt(i).toString(2), 8); // strings |
56 | | |
57 | 22 | output += cur; |
58 | | |
59 | | } |
60 | | |
61 | 4 | return output; |
62 | | |
63 | | }; |
64 | | |
65 | | |
66 | | // @param str {String} binary string |
67 | | // @return {String} Unicode string |
68 | 1 | binary.toUnicode = function(str) { |
69 | | |
70 | 2 | var arr = binary.split(str); |
71 | 2 | var output = ''; |
72 | | |
73 | 2 | for (var i = 0, len = arr.length; i < len; i++) { |
74 | 6 | var integer = binary.toInt(arr[i]); |
75 | 6 | output += String.fromCharCode(integer); |
76 | | } |
77 | | |
78 | 2 | return output; |
79 | | |
80 | | }; |
81 | | |
82 | | |
83 | | // ----- arithmetic |
84 | | // --------------------------------------- |
85 | | |
86 | | // @param a {String} binary number |
87 | | // @param b {String} binary number |
88 | | // @param len? {Number} optional bitLength restriction |
89 | 1 | binary.add = function(a, b, len) { |
90 | | |
91 | 35 | if (!len) { |
92 | 7 | a = parseInt(a, 2); |
93 | 7 | b = parseInt(b, 2); |
94 | 7 | return (a + b).toString(2); |
95 | | } |
96 | | |
97 | 28 | a = binary.pad(a, len); |
98 | 28 | b = binary.pad(b, len); |
99 | | |
100 | 28 | var result = ''; |
101 | 28 | var carry = '0'; |
102 | | |
103 | 28 | for (var i = len - 1; i >= 0; i--) { |
104 | | |
105 | 112 | var and = binary.and(a[i], b[i]); |
106 | 112 | var xor = binary.xor(a[i], b[i]); |
107 | 112 | var sum = binary.xor(xor, carry); |
108 | | |
109 | 112 | result = sum + result; |
110 | 112 | carry = binary.or(and, binary.and(xor, carry)); |
111 | | |
112 | | } |
113 | | |
114 | 28 | return result; |
115 | | |
116 | | }; |
117 | | |
118 | 1 | binary.addBits = function(a, b) { |
119 | | |
120 | 4 | a = a === '1' ? 1 : 0; |
121 | 4 | b = b === '1' ? 1 : 0; |
122 | | |
123 | 4 | var sum = a ^ b; |
124 | 4 | var carry = a & b; |
125 | | |
126 | 4 | return [sum.toString(), carry.toString()]; |
127 | | |
128 | | }; |
129 | | |
130 | | // @param a {String} binary number |
131 | | // @param b {String} binary number |
132 | | // todo: @param n {Number} optional bitLength restriction |
133 | 1 | binary.multiply = function(a, b) { |
134 | 6 | a = parseInt(a, 2); |
135 | 6 | b = parseInt(b, 2); |
136 | 6 | return (a * b).toString(2); |
137 | | }; |
138 | | |
139 | | // @param a {String} binary number |
140 | | // @param b {String} binary number |
141 | | // todo: @param n {Number} optional bitLength restriction |
142 | 1 | binary.divide = function(a, b) { |
143 | 6 | a = parseInt(a, 2); |
144 | 6 | b = parseInt(b, 2); |
145 | 6 | return (a / b).toString(2); |
146 | | }; |
147 | | |
148 | | |
149 | | // ----- logic |
150 | | // --------------------------------------- |
151 | 1 | binary.not = function(str) { |
152 | | |
153 | 14 | var inverse = ''; |
154 | | |
155 | 14 | for (var i = 0; i < str.length; i++) { |
156 | 87 | inverse += str[i] === '1' ? '0' : '1'; |
157 | | } |
158 | | |
159 | 14 | return inverse; |
160 | | |
161 | | }; |
162 | | |
163 | 1 | binary.and = function(a, b) { |
164 | | |
165 | 231 | var eq = binary.equalize(a, b); |
166 | 231 | a = eq[0]; |
167 | 231 | b = eq[1]; |
168 | | |
169 | 231 | var result = ''; |
170 | | |
171 | 231 | for (var i = 0; i < a.length; i++) { |
172 | 252 | if (a[i] === b[i]) { |
173 | 163 | result += a[i]; |
174 | | } |
175 | | else { |
176 | 89 | result += '0'; |
177 | | } |
178 | | } |
179 | | |
180 | 231 | return result; |
181 | | |
182 | | }; |
183 | | |
184 | 1 | binary.or = function(a, b) { |
185 | | |
186 | 120 | var eq = binary.equalize(a, b); |
187 | 120 | a = eq[0]; |
188 | 120 | b = eq[1]; |
189 | | |
190 | 120 | var result = ''; |
191 | | |
192 | 120 | for (var i = 0; i < a.length; i++) { |
193 | 144 | if (a[i] === '1' || b[i] === '1') { |
194 | 45 | result += '1'; |
195 | | } |
196 | | else { |
197 | 99 | result += '0'; |
198 | | } |
199 | | } |
200 | | |
201 | 120 | return result; |
202 | | |
203 | | }; |
204 | | |
205 | 1 | binary.nand = function(a, b) { |
206 | 3 | var and = binary.and(a, b); |
207 | 3 | return binary.not(and); |
208 | | }; |
209 | | |
210 | 1 | binary.nor = function(a, b) { |
211 | 4 | var or = binary.or(a, b); |
212 | 4 | return binary.not(or); |
213 | | }; |
214 | | |
215 | | // http://jsperf.com/bitwise-vs-string-operations |
216 | 1 | binary.xor = function(a, b) { |
217 | | |
218 | 228 | var eq = binary.equalize(a, b); |
219 | 228 | a = eq[0]; |
220 | 228 | b = eq[1]; |
221 | | |
222 | 228 | var result = ''; |
223 | | |
224 | 228 | for (var i = 0; i < a.length; i++) { |
225 | 240 | if (a[i] === b[i]) { |
226 | 160 | result += '0'; |
227 | | } |
228 | | else { |
229 | 80 | result += '1'; |
230 | | } |
231 | | } |
232 | | |
233 | 228 | return result; |
234 | | |
235 | | }; |
236 | | |
237 | 1 | binary.complement = function(str) { |
238 | 5 | var inverse = binary.not(str); |
239 | 5 | var complement = binary.add(inverse, 1); |
240 | 5 | return binary.pad(complement, str.length); |
241 | | }; |
242 | | |
243 | | |
244 | | // ----- etc |
245 | | // --------------------------------------- |
246 | | |
247 | | // @param str {String} binary string |
248 | | // @param n {Number} length of output |
249 | | // @return {String} left-padded binary string |
250 | 1 | binary.pad = function(str, n) { |
251 | 99 | while (str.length < n) { |
252 | 194 | str = '0' + str; |
253 | | } |
254 | 99 | return str; |
255 | | }; |
256 | | |
257 | | // @param str {String} binary string |
258 | | // @param n {Number} length of output |
259 | | // @param fn {Function} callback |
260 | | // @return {Function} callback(err, result) |
261 | 1 | binary.padSafe = function(str, n, fn) { |
262 | | |
263 | 2 | while (str.length < n) { |
264 | 4 | str = '0' + str; |
265 | | } |
266 | | |
267 | 2 | if (str.length > n) { |
268 | 1 | var err = new Error('input length exceeds expected length of output'); |
269 | 1 | return fn(err, str); |
270 | | } |
271 | | |
272 | 1 | return fn(null, str); |
273 | | |
274 | | }; |
275 | | |
276 | | // @param a {String} binary string |
277 | | // @param b {String} binary string |
278 | | // @return {Array} [(padded) a, (padded) b] |
279 | 1 | binary.equalize = function(a, b) { |
280 | | |
281 | 581 | var aLen = a.length; |
282 | 581 | var bLen = b.length; |
283 | | |
284 | 581 | if (aLen > bLen) { |
285 | 1 | b = binary.pad(b, aLen); |
286 | | } |
287 | | |
288 | 581 | if (bLen > aLen) { |
289 | 10 | a = binary.pad(a, bLen); |
290 | | } |
291 | | |
292 | 581 | return [a, b]; |
293 | | |
294 | | }; |
295 | | |
296 | | // @param str {String} binary string |
297 | | // @param len? {Number} optional number of characters per chunk; default is 8 |
298 | | // @return {Array} |
299 | 1 | binary.split = function(str, len) { |
300 | 6 | if (!len) { |
301 | 3 | len = 8; |
302 | | } |
303 | 6 | var regex = new RegExp('.{1,' + len + '}', 'g'); // /.{1,8}/g |
304 | 6 | return str.match(regex); |
305 | | }; |
306 | | |
307 | | // @param arr {Array} array of equal length binary strings |
308 | | // @return {String} least significant bits |
309 | 1 | binary.lsb = function(arr) { |
310 | | |
311 | 1 | var output = ''; |
312 | | |
313 | 1 | for (var i = 0, len = arr.length; i < len; i++) { |
314 | 14 | var byteLength = arr[i].length; |
315 | 14 | var bit = arr[i][byteLength - 1]; |
316 | 14 | var out = bit === '0' ? '0' : '1'; |
317 | 14 | output += out; |
318 | | } |
319 | | |
320 | 1 | return output; |
321 | | |
322 | | }; |