UNPKG

10.4 kBJavaScriptView Raw
1/*!
2 * n.js -> Arithmetic operations on big integers
3 * Pure javascript implementation, no external libraries needed
4 * Copyright(c) 2012 Alex Bardas <alexbardas@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.2.5";
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 (!n)
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)), x))
80 return
81 }
82 }
83
84 BigNumber.prototype.add_digit = function(digit, x) {
85 if (test_digit(digit))
86 this.number.push(digit);
87 else {
88 //throw (x || digit) + " is not a valid number";
89 this.number = errors['invalid'];
90 return false;
91 }
92
93 return this;
94 }
95
96 // returns:
97 // 0 if this.number == n
98 // -1 if this.number < n
99 // 1 if this.number > n
100 BigNumber.prototype._compare = function(n) {
101 // if the function is called with no arguments then return 0
102 if (!n)
103 return 0;
104
105 var x = new BigNumber(n), i;
106
107 // If the numbers have different signs, then the positive
108 // number is greater
109 if (this.sign !== x.sign)
110 return this.sign;
111
112 // Else, check the length
113 if (this.number.length > x.number.length)
114 return this.sign;
115 else if (this.number.length < x.number.length)
116 return this.sign*(-1);
117
118 // If they have similar length, compare the numbers
119 // digit by digit
120 for (i=this.number.length-1; i>=0; --i) {
121 if (this.number[i] > x.number[i])
122 return this.sign;
123 else if (this.number[i] < x.number[i])
124 return this.sign*(-1);
125 }
126
127 return 0;
128 }
129
130 // greater than
131 BigNumber.prototype.gt = function(n) {
132 return this._compare(n);
133 }
134
135 // greater than or equal
136 BigNumber.prototype.gte = function(n) {
137 return this._compare(n) >= 0;
138 }
139
140 // this.number equals n
141 BigNumber.prototype.equals = function(n) {
142 return this._compare(n) === 0;
143 }
144
145 // less than or equal
146 BigNumber.prototype.lte = function(n) {
147 return this._compare(n) <= 0;
148 }
149
150 // less than
151 BigNumber.prototype.lt = function(n) {
152 return this._compare(n) < 0;
153 }
154
155 // this.number + n
156 BigNumber.prototype.add = function(n) {
157 // if the function is called with no arguments then return
158 if (!n)
159 return this;
160 var x = new BigNumber(n);
161
162 if (this.sign !== x.sign) {
163 if (this.sign > 0) {
164 x.sign = 1;
165 return this.minus(x);
166 }
167 else {
168 this.sign = 1;
169 return x.minus(this);
170 }
171 }
172
173 this.number = BigNumber._add(this, x);
174 return this;
175 }
176
177 // this.number - n
178 BigNumber.prototype.subtract = function(n) {
179 // if the function is called with no arguments then return
180 if (!n)
181 return this;
182 var x = new BigNumber(n);
183
184 if (this.sign !== x.sign) {
185 this.number = BigNumber._add(this, x);
186 return this;
187 }
188
189 // if current number is lesser than x, final result will be negative
190 (this.lt(x)) ? this.sign = -1 : this.sign = 1;
191 (abs(this).lt(abs(x))) ?
192 this.number = BigNumber._subtract(x, this) :
193 this.number = BigNumber._subtract(this, x);
194
195 return this;
196 }
197
198 // adds two positive BigNumbers
199 BigNumber._add = function(a, b) {
200 var i, remainder = 0, length = Math.max(a.number.length, b.number.length);
201
202 for (i=0; i<length || remainder>0; ++i) {
203 a.number[i] = (remainder += (a.number[i] || 0) + (b.number[i] || 0)) % 10;
204 remainder = Math.floor(remainder/10)
205 }
206
207 return a.number;
208 }
209
210 // decreases b from a
211 // a and b are 2 positive BigNumbers and a > b
212 BigNumber._subtract = function(a, b) {
213 var i, remainder = 0, length = a.number.length;
214
215 for (i=0; i<length; ++i) {
216 a.number[i] -= (b.number[i] || 0) + remainder;
217 a.number[i] += (remainder = (a.number[i] < 0) ? 1 : 0) * 10;
218 }
219 // let's optimize a bit, and count the zeroes which need to be removed
220 i = 0, length = a.number.length-1;
221 while (a.number[length-i] === 0 && length-i > 0)
222 i++;
223 if (i>0)
224 a.number.splice(-i);
225 return a.number;
226 }
227
228 // this.number * n
229 BigNumber.prototype.multiply = function(n) {
230 // if the function is called with no arguments then return
231 if (!n && n != 0)
232 return this;
233 var x = new BigNumber(n), i, j, remainder = 0, result = [];
234 // test if one of the numbers is zero
235 if (this.isZero() || x.isZero()) {
236 return new BigNumber(0);
237 }
238
239 this.sign *= x.sign;
240
241 // multiply the numbers
242 for (i=0; i<this.number.length; ++i) {
243 for (remainder=0, j=0; j<x.number.length || remainder>0; ++j) {
244 result[i+j] = (remainder += (result[i+j] || 0) + this.number[i]*(x.number[j] || 0))%10;
245 remainder = Math.floor(remainder/10);
246 }
247 }
248
249 this.number = result;
250 return this;
251 }
252
253 // this.number / n
254 BigNumber.prototype.divide = function(n) {
255 // if the function is called with no arguments then return
256 if (!n && n != 0)
257 return this;
258 var x = new BigNumber(n), i, j, length, remainder = 0, result = [], rest = new BigNumber();
259 // test if one of the numbers is zero
260 if (x.isZero()) {
261 this.number = errors['division by zero']
262 return this;
263 }
264 else if (this.isZero()) {
265 return new BigNumber(0);
266 }
267 this.sign *= x.sign;
268 x.sign = 1;
269 // every number divided by 1 is the same number, so don't waste time dividing them
270 if (x.number.length === 1 && x.number[0] === 1)
271 return this;
272
273 for (i=this.number.length-1; i>=0; i--) {
274 rest.multiply(10);
275 rest.number[0] = this.number[i];
276 result[i] = 0;
277 while (x.lte(rest)) {
278 result[i]++;
279 rest.subtract(x);
280 }
281 }
282
283 i = 0, length = result.length-1;
284 while (result[length-i] === 0 && length-i > 0)
285 i++;
286 if (i>0)
287 result.splice(-i);
288
289 // returns the rest as a string
290 this.rest = rest.number.reverse().join().replace(/,/g,'');
291 this.number = result
292 return this;
293 }
294
295 // n must be a positive number
296 BigNumber.prototype.power = function(n) {
297 if (!n && n !== 0)
298 return;
299 var num;
300 // Convert the argument to a number
301 n = +n;
302 if (n === 0)
303 return new BigNumber(1);
304 if (n === 1)
305 return this;
306
307 num = new BigNumber(this, true);
308
309 this.number = [1];
310 while (n > 0) {
311 if (n % 2 === 1) {
312 this.multiply(num);
313 n--;
314 continue;
315 }
316 num.multiply(num);
317 n = Math.floor(n/2);
318 }
319
320 return this;
321 }
322
323 // |this.number|
324 BigNumber.prototype.abs = function() {
325 this.sign = 1;
326 return this;
327 }
328
329 // is this.number == 0 ?
330 BigNumber.prototype.isZero = function() {
331 return (this.number.length === 1 && this.number[0] === 0)
332 }
333
334 // this.number.toString()
335 BigNumber.prototype.toString = function() {
336 var i, x = '';
337 if (typeof this.number === "string")
338 return this.number;
339
340 for (i=this.number.length-1; i>=0; --i)
341 x += this.number[i];
342
343 return (this.sign > 0) ? x : ('-' + x);
344 }
345
346 // Use shorcuts for functions names
347 BigNumber.prototype.plus = BigNumber.prototype.add;
348 BigNumber.prototype.minus = BigNumber.prototype.subtract;
349 BigNumber.prototype.div = BigNumber.prototype.divide;
350 BigNumber.prototype.mult = BigNumber.prototype.multiply;
351 BigNumber.prototype.pow = BigNumber.prototype.power;
352 BigNumber.prototype.val = BigNumber.prototype.toString;
353})(this);