UNPKG

bigint

Version:

Arbitrary-precision integer arithmetic using libgmp

411 lines (351 loc) 10 kB
try { // node.js versions < 0.5.5 var cc = new require('./build/default/bigint'); } catch(e) { // node.js versions >= 0.5.5 var cc = new require('./build/Release/bigint'); } var BigInt = cc.BigInt; module.exports = BigInt; BigInt.conditionArgs = function(num, base) { if (typeof num !== 'string') num = num.toString(base || 10); if (num.match(/e\+/)) { // positive exponent if (!Number(num).toString().match(/e\+/)) { return { num: Math.floor(Number(num)).toString(), base: 10 }; } else { var pow = Math.ceil(Math.log(num) / Math.log(2)); var n = (num / Math.pow(2, pow)).toString(2) .replace(/^0/,''); var i = n.length - n.indexOf('.'); n = n.replace(/\./,''); for (; i <= pow; i++) n += '0'; return { num : n, base : 2, }; } } else if (num.match(/e\-/)) { // negative exponent return { num : Math.floor(Number(num)).toString(), base : base || 10 }; } else { return { num : num, base : base || 10, }; } }; cc.setJSConditioner(BigInt.conditionArgs); BigInt.prototype.inspect = function () { return '<BigInt ' + this.toString(10) + '>'; }; BigInt.prototype.toNumber = function () { return parseInt(this.toString(), 10); }; [ 'add', 'sub', 'mul', 'div', 'mod' ].forEach(function (op) { BigInt.prototype[op] = function (num) { if (num instanceof BigInt) { return this['b'+op](num); } else if (typeof num === 'number') { if (num >= 0) { return this['u'+op](num); } else if (op === 'add') { return this.usub(-num); } else if (op === 'sub') { return this.uadd(-num); } else { var x = BigInt(num); return this['b'+op](x); } } else if (typeof num === 'string') { var x = BigInt(num); return this['b'+op](x); } else { throw new TypeError('Unspecified operation for type ' + (typeof num) + ' for ' + op); } }; }); BigInt.prototype.abs = function () { return this.babs(); }; BigInt.prototype.neg = function () { return this.bneg(); }; BigInt.prototype.powm = function (num, mod) { var m, res; if ((typeof mod) === 'number' || (typeof mod) === 'string') { m = BigInt(mod); } else if (mod instanceof BigInt) { m = mod; } if ((typeof num) === 'number') { return this.upowm(num, m); } else if ((typeof num) === 'string') { var n = BigInt(num); return this.bpowm(n, m); } else if (num instanceof BigInt) { return this.bpowm(num, m); } }; BigInt.prototype.mod = function (num, mod) { var m, res; if ((typeof mod) === 'number' || (typeof mod) === 'string') { m = BigInt(mod); } else if (mod instanceof BigInt) { m = mod; } if ((typeof num) === 'number') { return this.umod(num, m); } else if ((typeof num) === 'string') { var n = BigInt(num); return this.bmod(n, m); } else if (num instanceof BigInt) { return this.bmod(num, m); } }; BigInt.prototype.pow = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.upow(num); } else { return BigInt.prototype.powm.call(this, num, this); } } else { var x = parseInt(num.toString(), 10); return BigInt.prototype.pow.call(this, x); } }; BigInt.prototype.shiftLeft = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.umul2exp(num); } else { return this.shiftRight(-num); } } else { var x = parseInt(num.toString(), 10); return BigInt.prototype.shiftLeft.call(this, x); } }; BigInt.prototype.shiftRight = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.udiv2exp(num); } else { return this.shiftLeft(-num); } } else { var x = parseInt(num.toString(), 10); return BigInt.prototype.shiftRight.call(this, x); } }; BigInt.prototype.cmp = function (num) { if (num instanceof BigInt) { return this.bcompare(num); } else if (typeof num === 'number') { if (num < 0) { return this.scompare(num); } else { return this.ucompare(num); } } else { var x = BigInt(num); return this.bcompare(x); } }; BigInt.prototype.gt = function (num) { return this.cmp(num) > 0; }; BigInt.prototype.ge = function (num) { return this.cmp(num) >= 0; }; BigInt.prototype.eq = function (num) { return this.cmp(num) === 0; }; BigInt.prototype.ne = function (num) { return this.cmp(num) !== 0; }; BigInt.prototype.lt = function (num) { return this.cmp(num) < 0; }; BigInt.prototype.le = function (num) { return this.cmp(num) <= 0; }; 'and or xor'.split(' ').forEach(function (name) { BigInt.prototype[name] = function (num) { if (num instanceof BigInt) { return this['b' + name](num); } else { var x = BigInt(num); return this['b' + name](x); } }; }); BigInt.prototype.sqrt = function() { return this.bsqrt(); }; BigInt.prototype.root = function(num) { if (num instanceof BigInt) { return this.broot(num); } else { var x = BigInt(num); return this.broot(num); } }; BigInt.prototype.rand = function (to) { if (to === undefined) { if (this.toString() === '1') { return BigInt(0); } else { return this.brand0(); } } else { var x = to instanceof BigInt ? to.sub(this) : BigInt(to).sub(this); return x.brand0().add(this); } }; BigInt.prototype.invertm = function (mod) { if (mod instanceof BigInt) { return this.binvertm(mod); } else { var x = BigInt(mod); return this.binvertm(x); } }; BigInt.prototype.probPrime = function (reps) { var n = this.probprime(reps || 10); return { 2 : true, 1 : 'maybe', 0 : false }[n]; }; BigInt.prototype.nextPrime = function () { return this.nextprime(); }; BigInt.prototype.gcd = function (num) { return this.bgcd(num); }; BigInt.fromBuffer = function (buf, opts) { if (!opts) opts = {}; var endian = { 1 : 'big', '-1' : 'little' }[opts.endian] || opts.endian || 'big' ; var size = opts.size || 1; if (buf.length % size !== 0) { throw new RangeError('Buffer length (' + buf.length + ')' + ' must be a multiple of size (' + size + ')' ); } var hex = []; for (var i = 0; i < buf.length; i += size) { var chunk = []; for (var j = 0; j < size; j++) { chunk.push(buf[ i + (endian === 'big' ? j : (size - j - 1)) ]); } hex.push(chunk .map(function (c) { return (c < 16 ? '0' : '') + c.toString(16); }) .join('') ); } return BigInt(hex.join(''), 16); }; BigInt.prototype.toBuffer = function (opts) { if (typeof opts === 'string') { if (opts !== 'mpint') return 'Unsupported Buffer representation'; var abs = this.abs(); var buf = abs.toBuffer({ size : 1, endian : 'big' }); var len = buf.length === 1 && buf[0] === 0 ? 0 : buf.length; if (buf[0] & 0x80) len ++; var ret = new Buffer(4 + len); if (len > 0) buf.copy(ret, 4 + (buf[0] & 0x80 ? 1 : 0)); if (buf[0] & 0x80) ret[4] = 0; ret[0] = len & (0xff << 24); ret[1] = len & (0xff << 16); ret[2] = len & (0xff << 8); ret[3] = len & (0xff << 0); // two's compliment for negative integers: var isNeg = this.lt(0); if (isNeg) { for (var i = 4; i < ret.length; i++) { ret[i] = 0xff - ret[i]; } } ret[4] = (ret[4] & 0x7f) | (isNeg ? 0x80 : 0); if (isNeg) ret[ret.length - 1] ++; return ret; } if (!opts) opts = {}; var endian = { 1 : 'big', '-1' : 'little' }[opts.endian] || opts.endian || 'big' ; var size = opts.size || 1; var hex = this.toString(16); if (hex.charAt(0) === '-') throw new Error( 'converting negative numbers to Buffers not supported yet' ); var len = Math.ceil(hex.length / (2 * size)) * size; var buf = new Buffer(len); // zero-pad the hex string so the chunks are all `size` long while (hex.length < 2 * len) hex = '0' + hex; var hx = hex .split(new RegExp('(.{' + (2 * size) + '})')) .filter(function (s) { return s.length > 0 }) ; hx.forEach(function (chunk, i) { for (var j = 0; j < size; j++) { var ix = i * size + (endian === 'big' ? j : size - j - 1); buf[ix] = parseInt(chunk.slice(j*2,j*2+2), 16); } }); return buf; }; Object.keys(BigInt.prototype).forEach(function (name) { if (name === 'inspect' || name === 'toString') return; BigInt[name] = function (num) { var args = [].slice.call(arguments, 1); if (num instanceof BigInt) { return num[name].apply(num, args); } else { var bigi = BigInt(num); return bigi[name].apply(bigi, args); } }; });