UNPKG

10.9 kBJavaScriptView Raw
1/*!
2 * n.js -> Arithmetic operations on big integers
3 * Pure javascript implementation, no external libraries needed
4 * Copyright(c) 2012-2014 Alex Bardas <alex.bardas@gmail.com>
5 * MIT Licensed
6 * It supports the following operations:
7 * addition, subtraction, multiplication, division, power, absolute value
8 * It works with both positive and negative integers
9 */
10
11;(function(exports, undefined) {
12
13 var version = "0.3.1";
14
15 // Helper function which tests if a given character is a digit
16 var test_digit = function(digit) {
17 return (/^\d$/.test(digit));
18 };
19 // Helper function which returns the absolute value of a given number
20 var abs = function(n) {
21 // if the function is called with no arguments then return
22 if (typeof n === 'undefined')
23 return;
24 var x = new BigNumber(n, true);
25 x.sign = 1;
26 return x;
27 };
28
29 exports.n = function (number) {
30 return new BigNumber(number);
31 };
32
33 var errors = {
34 "invalid": "Invalid Number",
35 "division by zero": "Invalid Number - Division By Zero"
36 };
37 // constructor function which creates a new BigNumber object
38 // from an integer, a string, an array or other BigNumber object
39 // if new_copy is true, the function returns a new object instance
40 var BigNumber = function(x, new_copy) {
41 var i;
42 this.number = [];
43 this.sign = 1;
44 this.rest = 0;
45
46 if (!x) {
47 this.number = [0];
48 return;
49 }
50
51 if (x.constructor === BigNumber) {
52 return new_copy ? new BigNumber(x.toString()) : x;
53 }
54
55 // x can be an array or object
56 // eg array: [3,2,1], ['+',3,2,1], ['-',3,2,1]
57 // eg string: '321', '+321', -321'
58 // every character except the first must be a digit
59
60 if (typeof x == 'object') {
61 if (x.length && x[0] === '-' || x[0] === '+') {
62 this.sign = x[0] === '+' ? 1 : -1;
63 x.shift(0);
64 }
65 for (i=x.length-1; i>=0; --i) {
66 if (!this.add_digit(x[i], x))
67 return;
68 }
69 }
70
71 else {
72 x = x.toString();
73 if (x.charAt(0) === '-' || x.charAt(0) === '+') {
74 this.sign = x.charAt(0) === '+' ? 1 : -1;
75 x = x.substring(1);
76 }
77
78 for (i=x.length-1; i>=0; --i) {
79 if (!this.add_digit(parseInt(x.charAt(i), 10), x)) {
80 return;
81 }
82 }
83 }
84 };
85
86 BigNumber.prototype.add_digit = function(digit, x) {
87 if (test_digit(digit))
88 this.number.push(digit);
89 else {
90 //throw (x || digit) + " is not a valid number";
91 this.number = errors['invalid'];
92 return false;
93 }
94
95 return this;
96 };
97
98 // returns:
99 // 0 if this.number === n
100 // -1 if this.number < n
101 // 1 if this.number > n
102 BigNumber.prototype._compare = function(n) {
103 // if the function is called with no arguments then return 0
104 if (typeof n === 'undefined')
105 return 0;
106
107 var x = new BigNumber(n);
108 var i;
109
110 // If the numbers have different signs, then the positive
111 // number is greater
112 if (this.sign !== x.sign)
113 return this.sign;
114
115 // Else, check the length
116 if (this.number.length > x.number.length)
117 return this.sign;
118 else if (this.number.length < x.number.length)
119 return this.sign*(-1);
120
121 // If they have similar length, compare the numbers
122 // digit by digit
123 for (i = this.number.length-1; i >= 0; --i) {
124 if (this.number[i] > x.number[i])
125 return this.sign;
126 else if (this.number[i] < x.number[i])
127 return this.sign * (-1);
128 }
129
130 return 0;
131 };
132
133 // greater than
134 BigNumber.prototype.gt = function(n) {
135 return this._compare(n) > 0;
136 };
137
138 // greater than or equal
139 BigNumber.prototype.gte = function(n) {
140 return this._compare(n) >= 0;
141 };
142
143 // this.number equals n
144 BigNumber.prototype.equals = function(n) {
145 return this._compare(n) === 0;
146 };
147
148 // less than or equal
149 BigNumber.prototype.lte = function(n) {
150 return this._compare(n) <= 0;
151 };
152
153 // less than
154 BigNumber.prototype.lt = function(n) {
155 return this._compare(n) < 0;
156 };
157
158 // this.number + n
159 BigNumber.prototype.add = function(n) {
160 // if the function is called with no arguments then return
161 if (typeof n === 'undefined')
162 return this;
163 var x = new BigNumber(n);
164
165 if (this.sign !== x.sign) {
166 if (this.sign > 0) {
167 x.sign = 1;
168 return this.minus(x);
169 }
170 else {
171 this.sign = 1;
172 return x.minus(this);
173 }
174 }
175
176 this.number = BigNumber._add(this, x);
177 return this;
178 };
179
180 // this.number - n
181 BigNumber.prototype.subtract = function(n) {
182 // if the function is called with no arguments then return
183 if (typeof n === 'undefined')
184 return this;
185 var x = new BigNumber(n);
186
187 if (this.sign !== x.sign) {
188 this.number = BigNumber._add(this, x);
189 return this;
190 }
191
192 // if current number is lesser than x, final result will be negative
193 this.sign = (this.lt(x)) ? -1 : 1;
194 this.number = (abs(this).lt(abs(x))) ?
195 BigNumber._subtract(x, this) :
196 BigNumber._subtract(this, x);
197
198 return this;
199 };
200
201 // adds two positive BigNumbers
202 BigNumber._add = function(a, b) {
203 var i;
204 var remainder = 0;
205 var length = Math.max(a.number.length, b.number.length);
206
207 for (i = 0; i < length || remainder > 0; ++i) {
208 a.number[i] = (remainder += (a.number[i] || 0) + (b.number[i] || 0)) % 10;
209 remainder = Math.floor(remainder/10);
210 }
211
212 return a.number;
213 };
214
215 // decreases b from a
216 // a and b are 2 positive BigNumbers and a > b
217 BigNumber._subtract = function(a, b) {
218 var i;
219 var remainder = 0;
220 var length = a.number.length;
221
222 for (i = 0; i < length; ++i) {
223 a.number[i] -= (b.number[i] || 0) + remainder;
224 a.number[i] += (remainder = (a.number[i] < 0) ? 1 : 0) * 10;
225 }
226 // let's optimize a bit, and count the zeroes which need to be removed
227 i = 0;
228 length = a.number.length - 1;
229 while (a.number[length - i] === 0 && length - i > 0)
230 i++;
231 if (i > 0)
232 a.number.splice(-i);
233 return a.number;
234 };
235
236 // this.number * n
237 BigNumber.prototype.multiply = function(n) {
238 // if the function is called with no arguments then return
239 if (typeof n === 'undefined')
240 return this;
241 var x = new BigNumber(n);
242 var i;
243 var j;
244 var remainder = 0;
245 var result = [];
246 // test if one of the numbers is zero
247 if (this.isZero() || x.isZero()) {
248 return new BigNumber(0);
249 }
250
251 this.sign *= x.sign;
252
253 // multiply the numbers
254 for (i = 0; i < this.number.length; ++i) {
255 for (remainder = 0, j = 0; j < x.number.length || remainder > 0; ++j) {
256 result[i + j] = (remainder += (result[i + j] || 0) + this.number[i] * (x.number[j] || 0)) % 10;
257 remainder = Math.floor(remainder / 10);
258 }
259 }
260
261 this.number = result;
262 return this;
263 };
264
265 // this.number / n
266 BigNumber.prototype.divide = function(n) {
267 // if the function is called with no arguments then return
268 if (typeof n === 'undefined') {
269 return this;
270 }
271 var x = new BigNumber(n);
272 var i;
273 var j;
274 var length;
275 var remainder = 0;
276 var result = [];
277 var rest = new BigNumber();
278 // test if one of the numbers is zero
279 if (x.isZero()) {
280 this.number = errors['division by zero'];
281 return this;
282 }
283 else if (this.isZero()) {
284 return new BigNumber(0);
285 }
286 this.sign *= x.sign;
287 x.sign = 1;
288 // every number divided by 1 is the same number, so don't waste time dividing them
289 if (x.number.length === 1 && x.number[0] === 1)
290 return this;
291
292 for (i = this.number.length - 1; i >= 0; i--) {
293 rest.multiply(10);
294 rest.number[0] = this.number[i];
295 result[i] = 0;
296 while (x.lte(rest)) {
297 result[i]++;
298 rest.subtract(x);
299 }
300 }
301
302 i = 0;
303 length = result.length-1;
304 while (result[length - i] === 0 && length - i > 0)
305 i++;
306 if (i > 0)
307 result.splice(-i);
308
309 // returns the rest as a string
310 this.rest = rest;
311 this.number = result;
312 return this;
313 };
314
315 // this.number % n
316 BigNumber.prototype.mod = function(n) {
317 return this.divide(n).rest;
318 };
319
320 // n must be a positive number
321 BigNumber.prototype.power = function(n) {
322 if (typeof n === 'undefined')
323 return;
324 var num;
325 // Convert the argument to a number
326 n = +n;
327 if (n === 0)
328 return new BigNumber(1);
329 if (n === 1)
330 return this;
331
332 num = new BigNumber(this, true);
333
334 this.number = [1];
335 while (n > 0) {
336 if (n % 2 === 1) {
337 this.multiply(num);
338 n--;
339 continue;
340 }
341 num.multiply(num);
342 n = Math.floor(n / 2);
343 }
344
345 return this;
346 };
347
348 // |this.number|
349 BigNumber.prototype.abs = function() {
350 this.sign = 1;
351 return this;
352 };
353
354 // is this.number == 0 ?
355 BigNumber.prototype.isZero = function() {
356 return (this.number.length === 1 && this.number[0] === 0);
357 };
358
359 // this.number.toString()
360 BigNumber.prototype.toString = function() {
361 var i;
362 var x = '';
363 if (typeof this.number === "string")
364 return this.number;
365
366 for (i = this.number.length-1; i >= 0; --i)
367 x += this.number[i];
368
369 return (this.sign > 0) ? x : ('-' + x);
370 };
371
372 // Use shorcuts for functions names
373 BigNumber.prototype.plus = BigNumber.prototype.add;
374 BigNumber.prototype.minus = BigNumber.prototype.subtract;
375 BigNumber.prototype.div = BigNumber.prototype.divide;
376 BigNumber.prototype.mult = BigNumber.prototype.multiply;
377 BigNumber.prototype.pow = BigNumber.prototype.power;
378 BigNumber.prototype.val = BigNumber.prototype.toString;
379})(this);