Skip to content

Instantly share code, notes, and snippets.

@dsamarin
Created October 3, 2011 03:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dsamarin/1258348 to your computer and use it in GitHub Desktop.
Save dsamarin/1258348 to your computer and use it in GitHub Desktop.
Arbitrary-precision numbers in JavaScript
"use strict";
// http://kickjava.com/src/java/math/MutableBigInteger.java.htm
String.prototype.repeat = function(i) {
var d = '', t = this;
while (i) {
if (i & 1) {
d += t;
}
t += t;
i >>= 1;
}
return d;
};
var Integer = function(number) {
number = number | 0;
this.signed = 0; // 0 is positive, 1 is negative
this.data = [number];
this.size = 1;
this.offset = 0;
};
Integer.bits_set = function(w) {
return (w<32768?(w<128?(w<8?(w<2?(w<1?(w<0?32:0):1):(w<4?2:3)):(w<32?(w<16?4:5):(w<64?6:7))):(w<2048?(w<512?(w<256?8:9):(w<1024?10:11)):(w<8192?(w<4096?12:13):(w<16384?14:15)))):(w<8388608?(w<524288?(w<131072?(w<65536?16:17):(w<262144?18:19)):(w<2097152?(w<1048576?20:21):(w<4194304?22:23))):(w<134217728?(w<33554432?(w<16777216?24:25):(w<67108864?26:27)):(w<536870912?(w<268435456?28:29):(w<1073741824?30:31)))));
};
Integer.prototype.toString = function() {
var size, result, segment, ch;
size = this.size;
/* Special case integer is representable
* by a JavaScript number
*/
if (size < 2) {
return (this.sign ? "-" : "") +
String(this.data[0] >>>= 0);
}
result = [];
while (size--) {
segment = this.data[size];
for (;;) {
ch = segment % 10 + 48;
result.push (ch);
if (segment < 10) break;
segment /= 10;
}
}
if (this.signed) result.push (45);
return String.fromCharCode.apply(null, result.reverse());
};
Integer.prototype.toString = function() {
var result, size, data, str, n;
result = [];
size = this.size;
data = this.data;
while (size--) {
n = data[size] >>> 0;
str = n.toString(2).replace(/0/g, '-').replace(/1/g, '@');
str = "-".repeat(32 - str.length) + str;
result.push (str);
}
return result.reverse().join("");
};
Integer.prototype.cmp = function(num) {
var size, i, b1, b2;
size = this.size;
if (size < num.size) {
return -1;
}
if (size > num.size) {
return 1;
}
for (i = 0; i < size; i++) {
b1 = this.data[this.offset + i];
b2 = num.data[num.offset + i];
if (b1 < b2) return -1;
if (b1 > b2) return 1;
}
return 0;
};
Integer.prototype.shl = function(amt) {
var data, offset, size, nints, nbits, hibits;
var newlen, i;
data = this.data;
size = this.size;
offset = this.offset;
if (size === 0) return;
nints = amt >>> 5;
nbits = amt & 0x1F;
hibits = Integer.bits_set (data[offset]);
if (amt <= (32 - hibits)) {
return this.prim_shl (nbits);
}
newlen = size + nints + 1;
if (nbits <= (32 - hibits)) newlen--;
/* TODO: I have a feeling this could be made better */
if (data.length < newlen) {
// The array must grow
var result = [];
for (i = 0; i < size; i++) {
result[i] = data[offset + i];
}
this.data = result;
this.offset = 0;
this.size = result.length = newlen;
} else if (data.length - offset >= newlen) {
// Use space on right
for (i = 0; i < newlen - size; i++) {
data[offset + size + i] = 0;
}
} else {
// Must use space on left
for (i = 0; i < size; i++) {
data[i] = data[offset + i];
}
for (i = size; i < newlen; i++) {
data[i] = 0;
}
this.offset = 0;
}
this.size = newlen;
if (nbits === 0) return;
if (nbits <= (32 - hibits)) {
this.prim_shl (nbits);
} else {
this.prim_shr (32 - nbits);
}
};
Integer.prototype.shr = function(amt) {
var data, size, offset, nints, nbits, hibits;
data = this.data;
size = this.size;
offset = this.offset;
if (size === 0) return;
nints = amt >>> 5;
nbits = amt & 0x1F;
size -= nints;
if (nbits == 0) return;
hibits = Integer.bits_set (data[offset]);
if (nbits >= hibits) {
this.prim_shl (32 - nbits);
this.size--;
} else {
this.prim_shr (nbits);
}
};
Integer.prototype.prim_shr = function(amt) {
var data, size, offset, n, i, c, b;
data = this.data;
size = this.size;
offset = this.offset;
n = 32 - amt;
i = offset + size - 1;
c = data[i];
while (i > offset) {
b = c;
c = data[i-1];
data[i] = (c << n) | (b >>> amt);
i--;
}
data[offset] >>>= amt;
};
Integer.prototype.prim_shl = function(amt) {
var data, size, offset, n, i, m, c, b;
data = this.data;
size = this.size;
offset = this.offset;
n = 32 - amt;
i = offset;
c = data[i];
m = i + size - 1;
while (i < m) {
b = c;
c = data[i + 1];
data[i] = (b << amt) | (c >>> n);
i++;
}
data[offset + size - 1] <<= amt;
};
Integer.prototype.add;
Integer.prototype.sub;
Integer.prototype.mul;
Integer.prototype.div;
var repl = require('repl');
repl.start().context.Integer = Integer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment