Created
October 3, 2011 03:07
-
-
Save dsamarin/1258348 to your computer and use it in GitHub Desktop.
Arbitrary-precision numbers in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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