mirror of
https://github.com/schibo/1964js.git
synced 2025-04-02 10:52:54 -04:00
git-svn-id: http://1964js.googlecode.com/svn/trunk@108 0378edba-076e-5dc0-2bb2-d87a714dcd81
685 lines
No EOL
13 KiB
JavaScript
685 lines
No EOL
13 KiB
JavaScript
// BigInt.js - Arbitrary size integer math package for JavaScript
|
|
// Copyright (C) 2000 Masanao Izumo <iz@onicos.co.jp>
|
|
// Version: 1.0.1
|
|
// Licence: GPL
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
//
|
|
// Interfaces:
|
|
// x = new BigInt("1234567890123456789012345678901234567890");
|
|
// y = new BigInt("0x123456789abcdef0123456789abcdef0");
|
|
// z = x.clone();
|
|
// z = bigint_uminus(x);
|
|
// z = bigint_plus(x, y);
|
|
// z = bigint_minus(x, y);
|
|
// z = bigint_mul(x, y);
|
|
// z = bigint_div(x, y);
|
|
// z = bigint_mod(x, y);
|
|
// cmp = bigint_cmp(x, y); /* return -1, 0, or 1 */
|
|
// num = bigint_number(x); /* convert normal number (may be floating) */
|
|
//
|
|
|
|
function _BigInt_toString()
|
|
{
|
|
return this.toStringBase(10);
|
|
}
|
|
function _BigInt_toStringBase(base)
|
|
{
|
|
var i, j, hbase;
|
|
var t;
|
|
var ds;
|
|
var c;
|
|
|
|
i = this.len;
|
|
if(i == 0)
|
|
return "0";
|
|
if(i == 1 && !this.digits[0])
|
|
return "0";
|
|
|
|
switch(base) {
|
|
default:
|
|
case 10:
|
|
j = Math.floor((2*8*i*241)/800)+2;
|
|
hbase = 10000;
|
|
break;
|
|
|
|
case 16:
|
|
j = Math.floor((2*8*i)/4)+2;
|
|
hbase = 0x10000;
|
|
break;
|
|
|
|
case 8:
|
|
j = (2*8*i)+2;
|
|
hbase = 010000;
|
|
break;
|
|
|
|
case 2:
|
|
j = (2*8*i)+2;
|
|
hbase = 020;
|
|
break;
|
|
}
|
|
|
|
t = this.clone();
|
|
ds = t.digits;
|
|
s = "";
|
|
|
|
while (i && j) {
|
|
var k = i;
|
|
var num = 0;
|
|
|
|
while (k--) {
|
|
num = (num<<16) + ds[k];
|
|
if(num < 0) num += 4294967296;
|
|
ds[k] = Math.floor(num / hbase);
|
|
num %= hbase;
|
|
}
|
|
|
|
if (ds[i-1] == 0)
|
|
i--;
|
|
k = 4;
|
|
while (k--) {
|
|
c = (num % base);
|
|
s = "0123456789abcdef".charAt(c) + s;
|
|
--j;
|
|
num = Math.floor(num / base);
|
|
if (i == 0 && num == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
while(i < s.length && s.charAt(i) == "0")
|
|
i++;
|
|
if(i)
|
|
s = s.substring(i, s.length);
|
|
if(!this.sign)
|
|
s = "-" + s;
|
|
return s;
|
|
}
|
|
function _BigInt_clone()
|
|
{
|
|
var x, i;
|
|
|
|
x = new BigInt(this.len, this.sign);
|
|
for(i = 0; i < this.len; i++)
|
|
x.digits[i] = this.digits[i];
|
|
return x;
|
|
}
|
|
|
|
function BigInt(len, sign)
|
|
{
|
|
var i, x, need_init;
|
|
|
|
// Setup member functions.
|
|
// Note: There is G.C. bug of function() in Netscape!
|
|
// Don't use anonymous function.
|
|
this.toString = _BigInt_toString;
|
|
this.toStringBase = _BigInt_toStringBase;
|
|
this.clone = _BigInt_clone;
|
|
|
|
if(BigInt.arguments.length == 0) {
|
|
this.sign = true;
|
|
this.len = len = 1;
|
|
this.digits = new Array(1);
|
|
need_init = true;
|
|
} else if(BigInt.arguments.length == 1) {
|
|
x = bigint_from_any(BigInt.arguments[0]);
|
|
if(x == BigInt.arguments[0])
|
|
x = x.clone();
|
|
this.sign = x.sign;
|
|
this.len = x.len;
|
|
this.digits = x.digits;
|
|
need_init = false;
|
|
} else {
|
|
this.sign = (sign ? true : false);
|
|
this.len = len;
|
|
this.digits = new Array(len);
|
|
need_init = true;
|
|
}
|
|
|
|
if(need_init) {
|
|
for(i = 0; i < len; i++)
|
|
this.digits[i] = 0;
|
|
}
|
|
}
|
|
|
|
function bigint_norm(x)
|
|
{
|
|
var len = x.len;
|
|
var ds = x.digits;
|
|
|
|
while(len-- && !ds[len])
|
|
;
|
|
x.len = ++len;
|
|
return x;
|
|
}
|
|
|
|
function bigint_from_int(n)
|
|
{
|
|
var sign, big, i;
|
|
|
|
if(n < 0) {
|
|
n = -n;
|
|
sign = false;
|
|
} else
|
|
sign = true;
|
|
n &= 0x7fffffff;
|
|
|
|
if(n <= 0xffff) {
|
|
big = new BigInt(1, 1);
|
|
big.digits[0] = n;
|
|
} else {
|
|
big = new BigInt(2, 1);
|
|
big.digits[0] = (n & 0xffff);
|
|
big.digits[1] = ((n>>16) & 0xffff);
|
|
}
|
|
return big;
|
|
}
|
|
|
|
function bigint_from_string(str, base)
|
|
{
|
|
var str_i;
|
|
var sign = true;
|
|
var c;
|
|
var len;
|
|
var z;
|
|
var zds;
|
|
var num;
|
|
var i;
|
|
var blen = 1;
|
|
|
|
str += "@"; // Terminator;
|
|
|
|
str_i = 0;
|
|
// TODO: skip white spaces
|
|
|
|
if(str.charAt(str_i) == "+") {
|
|
str_i++;
|
|
}
|
|
else if (str.charAt(str_i) == "-") {
|
|
str_i++;
|
|
sign = false;
|
|
}
|
|
|
|
if (str.charAt(str_i) == "@")
|
|
return null;
|
|
|
|
if (!base) {
|
|
if (str.charAt(str_i) == "0") {
|
|
c = str.charAt(str_i + 1);
|
|
if (c == "x" || c == "X") {
|
|
base = 16;
|
|
}
|
|
else if (c == "b" || c == "B") {
|
|
base = 2;
|
|
}
|
|
else {
|
|
base = 8;
|
|
}
|
|
}
|
|
else {
|
|
base = 10;
|
|
}
|
|
}
|
|
|
|
if (base == 8) {
|
|
while (str.charAt(str_i) == "0")
|
|
str_i++;
|
|
len = 3 * (str.length - str_i);
|
|
}
|
|
else { // base == 10, 2 or 16
|
|
if (base == 16 && str.charAt(str_i) == '0' && (str.charAt(str_i+1) == "x" || str.charAt(str_i+1) == "X")) {
|
|
str_i += 2;
|
|
}
|
|
if (base == 2 && str.charAt(str_i) == '0' && (str.charAt(str_i+1) == "b"||str.charAt(str_i+1) == "B")) {
|
|
str_i += 2;
|
|
}
|
|
while (str.charAt(str_i) == "0")
|
|
str_i++;
|
|
if (str.charAt(str_i) == "@") str_i--;
|
|
len = 4 * (str.length - str_i);
|
|
}
|
|
|
|
len = (len>>4)+1;
|
|
z = new BigInt(len, sign);
|
|
zds = z.digits;
|
|
|
|
while(true) {
|
|
c = str.charAt(str_i++);
|
|
if(c == "@")
|
|
break;
|
|
switch (c) {
|
|
case '0': c = 0; break;
|
|
case '1': c = 1; break;
|
|
case '2': c = 2; break;
|
|
case '3': c = 3; break;
|
|
case '4': c = 4; break;
|
|
case '5': c = 5; break;
|
|
case '6': c = 6; break;
|
|
case '7': c = 7; break;
|
|
case '8': c = 8; break;
|
|
case '9': c = 9; break;
|
|
case 'a': case 'A': c = 10; break;
|
|
case 'b': case 'B': c = 11; break;
|
|
case 'c': case 'C': c = 12; break;
|
|
case 'd': case 'D': c = 13; break;
|
|
case 'e': case 'E': c = 14; break;
|
|
case 'f': case 'F': c = 15; break;
|
|
default:
|
|
c = base;
|
|
break;
|
|
}
|
|
if (c >= base)
|
|
break;
|
|
|
|
i = 0;
|
|
num = c;
|
|
while(true) {
|
|
while (i<blen) {
|
|
num += zds[i]*base;
|
|
zds[i++] = (num & 0xffff);
|
|
num >>>= 16;
|
|
}
|
|
if (num) {
|
|
blen++;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return bigint_norm(z);
|
|
}
|
|
|
|
function bigint_from_any(x)
|
|
{
|
|
if(typeof(x) == "object") {
|
|
if(x.constructor == BigInt)
|
|
return x;
|
|
return BigInt(1, 1);
|
|
}
|
|
|
|
if(typeof(x) == "string") {
|
|
return bigint_from_string(x);
|
|
}
|
|
|
|
if(typeof(x) == "number") {
|
|
var i, x1, x2, fpt, np;
|
|
|
|
if(-2147483647 <= x && x <= 2147483647) {
|
|
return bigint_from_int(x);
|
|
}
|
|
x = x + "";
|
|
i = x.indexOf("e", 0);
|
|
if(i == -1)
|
|
return bigint_from_string(x);
|
|
x1 = x.substr(0, i);
|
|
x2 = x.substr(i+2, x.length - (i+2));
|
|
|
|
fpt = x1.indexOf(".", 0);
|
|
if(fpt != -1) {
|
|
np = x1.length - (fpt+1);
|
|
x1 = x1.substr(0, fpt) + x1.substr(fpt+1, np);
|
|
x2 = parseInt(x2) - np;
|
|
} else {
|
|
x2 = parseInt(x2);
|
|
}
|
|
while(x2-- > 0) {
|
|
x1 += "0";
|
|
}
|
|
return bigint_from_string(x1);
|
|
}
|
|
return BigInt(1, 1);
|
|
}
|
|
|
|
function bigint_uminus(x)
|
|
{
|
|
var z = x.clone();
|
|
z.sign = !z.sign;
|
|
return bigint_norm(z);
|
|
}
|
|
|
|
function bigint_add_internal(x, y, sign)
|
|
{
|
|
var z;
|
|
var num;
|
|
var i, len;
|
|
|
|
sign = (sign == y.sign);
|
|
if (x.sign != sign) {
|
|
if (sign)
|
|
return bigint_sub_internal(y, x);
|
|
return bigint_sub_internal(x, y);
|
|
}
|
|
|
|
if (x.len > y.len) {
|
|
len = x.len + 1;
|
|
z = x; x = y; y = z;
|
|
} else {
|
|
len = y.len + 1;
|
|
}
|
|
z = new BigInt(len, sign);
|
|
|
|
len = x.len;
|
|
for (i = 0, num = 0; i < len; i++) {
|
|
num += x.digits[i] + y.digits[i];
|
|
z.digits[i] = (num & 0xffff);
|
|
num >>>= 16;
|
|
}
|
|
len = y.len;
|
|
while (num && i < len) {
|
|
num += y.digits[i];
|
|
z.digits[i++] = (num & 0xffff);
|
|
num >>>= 16;
|
|
}
|
|
while (i < len) {
|
|
z.digits[i] = y.digits[i];
|
|
i++;
|
|
}
|
|
z.digits[i] = (num & 0xffff);
|
|
return bigint_norm(z);
|
|
// return z;
|
|
}
|
|
|
|
function bigint_sub_internal(x, y)
|
|
{
|
|
var z = 0;
|
|
var zds;
|
|
var num;
|
|
var i;
|
|
|
|
i = x.len;
|
|
// if x is larger than y, swap
|
|
if (x.len < y.len) {
|
|
z = x; x = y; y = z; // swap x y
|
|
}
|
|
else if (x.len == y.len) {
|
|
while (i > 0) {
|
|
i--;
|
|
if (x.digits[i] > y.digits[i]) {
|
|
break;
|
|
}
|
|
if (x.digits[i] < y.digits[i]) {
|
|
z = x; x = y; y = z; // swap x y
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
z = new BigInt(x.len, (z == 0) ? 1 : 0);
|
|
zds = z.digits;
|
|
|
|
for (i = 0, num = 0; i < y.len; i++) {
|
|
num += x.digits[i] - y.digits[i];
|
|
zds[i] = (num & 0xffff);
|
|
num >>>= 16;
|
|
}
|
|
while (num && i < x.len) {
|
|
num += x.digits[i];
|
|
zds[i++] = (num & 0xffff);
|
|
num >>>= 16;
|
|
}
|
|
while (i < x.len) {
|
|
zds[i] = x.digits[i];
|
|
i++;
|
|
}
|
|
|
|
return bigint_norm(z);
|
|
}
|
|
|
|
function bigint_plus(x, y)
|
|
{
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
return bigint_add_internal(x, y, 1);
|
|
}
|
|
|
|
function bigint_minus(x, y)
|
|
{
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
return bigint_add_internal(x, y, 0);
|
|
}
|
|
|
|
function bigint_mul(x, y)
|
|
{
|
|
var i, j;
|
|
var n = 0;
|
|
var z;
|
|
var zds, xds, yds;
|
|
var dd, ee;
|
|
var ylen;
|
|
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
|
|
j = x.len + y.len + 1;
|
|
z = new BigInt(j, x.sign == y.sign);
|
|
|
|
xds = x.digits;
|
|
yds = y.digits;
|
|
zds = z.digits;
|
|
ylen = y.len;
|
|
while (j--)
|
|
zds[j] = 0;
|
|
for (i = 0; i < x.len; i++) {
|
|
dd = xds[i];
|
|
if (dd == 0)
|
|
continue;
|
|
n = 0;
|
|
for (j = 0; j < ylen; j++) {
|
|
ee = n + dd * yds[j];
|
|
n = zds[i + j] + ee;
|
|
if (ee)
|
|
zds[i + j] = (n & 0xffff);
|
|
n >>>= 16;
|
|
}
|
|
if (n) {
|
|
zds[i + j] = n;
|
|
}
|
|
}
|
|
|
|
return bigint_norm(z);
|
|
}
|
|
|
|
function bigint_divmod(x, y, modulo)
|
|
{
|
|
var nx = x.len;
|
|
var ny = y.len;
|
|
var i, j;
|
|
var yy, z;
|
|
var xds, yds, zds, tds;
|
|
var t2;
|
|
var num;
|
|
var dd, q;
|
|
var ee;
|
|
var mod, div;
|
|
|
|
yds = y.digits;
|
|
if (ny == 0 && yds[0] == 0)
|
|
return null; // Division by zero
|
|
|
|
if (nx < ny || nx == ny && x.digits[nx - 1] < y.digits[ny - 1]) {
|
|
if (modulo)
|
|
return bigint_norm(x);
|
|
return BigInt(1, 1);
|
|
}
|
|
|
|
xds = x.digits;
|
|
if (ny == 1) {
|
|
dd = yds[0];
|
|
z = x.clone();
|
|
zds = z.digits;
|
|
t2 = 0;
|
|
i = nx;
|
|
while (i--) {
|
|
t2 = t2 * 65536 + zds[i];
|
|
zds[i] = (t2 / dd) & 0xffff;
|
|
t2 %= dd;
|
|
}
|
|
z.sign = (x.sign == y.sign);
|
|
if (modulo) {
|
|
if (!x.sign)
|
|
t2 = -t2;
|
|
if (x.sign != y.sign) {
|
|
t2 = t2 + yds[0] * (y.sign ? 1 : -1);
|
|
}
|
|
return bigint_from_int(t2);
|
|
}
|
|
return bigint_norm(z);
|
|
}
|
|
|
|
z = new BigInt(nx == ny ? nx + 2 : nx + 1,
|
|
x.sign == y.sign);
|
|
zds = z.digits;
|
|
if (nx == ny)
|
|
zds[nx + 1] = 0;
|
|
while (!yds[ny - 1])
|
|
ny--;
|
|
if ((dd = ((65536/(yds[ny-1]+1)) & 0xffff)) != 1) {
|
|
yy = y.clone();
|
|
tds = yy.digits;
|
|
j = 0;
|
|
num = 0;
|
|
while (j<ny) {
|
|
num += yds[j]*dd;
|
|
tds[j++] = num & 0xffff;
|
|
num >>= 16;
|
|
}
|
|
yds = tds;
|
|
j = 0;
|
|
num = 0;
|
|
while (j<nx) {
|
|
num += xds[j] * dd;
|
|
zds[j++] = num & 0xffff;
|
|
num >>= 16;
|
|
}
|
|
zds[j] = num & 0xffff;
|
|
}
|
|
else {
|
|
zds[nx] = 0;
|
|
j = nx;
|
|
while (j--) zds[j] = xds[j];
|
|
}
|
|
j = nx==ny?nx+1:nx;
|
|
do {
|
|
if (zds[j] == yds[ny-1]) q = 65535;
|
|
else q = ((zds[j]*65536 + zds[j-1])/yds[ny-1]) & 0xffff;
|
|
if (q) {
|
|
i = 0; num = 0; t2 = 0;
|
|
do { // multiply and subtract
|
|
t2 += yds[i] * q;
|
|
ee = num - (t2 & 0xffff);
|
|
num = zds[j - ny + i] + ee;
|
|
if (ee) zds[j - ny + i] = num & 0xffff;
|
|
num >>= 16;
|
|
t2 >>>= 16;
|
|
} while (++i < ny);
|
|
num += zds[j - ny + i] - t2; // borrow from high digit; don't update
|
|
while (num) { // "add back" required
|
|
i = 0; num = 0; q--;
|
|
do {
|
|
ee = num + yds[i];
|
|
num = zds[j - ny + i] + ee;
|
|
if (ee) zds[j - ny + i] = num & 0xffff;
|
|
num >>= 16;
|
|
} while (++i < ny);
|
|
num--;
|
|
}
|
|
}
|
|
zds[j] = q;
|
|
} while (--j >= ny);
|
|
|
|
if (modulo) { // just normalize remainder
|
|
mod = z.clone();
|
|
if (dd) {
|
|
zds = mod.digits;
|
|
t2 = 0; i = ny;
|
|
while (i--) {
|
|
t2 = (t2*65536) + zds[i];
|
|
zds[i] = (t2 / dd) & 0xffff;
|
|
t2 %= dd;
|
|
}
|
|
}
|
|
mod.len = ny;
|
|
mod.sign = x.sign;
|
|
if (x.sign != y.sign) {
|
|
return bigint_add_internal(mod, y, 1);
|
|
}
|
|
return bigint_norm(mod);
|
|
}
|
|
|
|
div = z.clone();
|
|
zds = div.digits;
|
|
j = (nx==ny ? nx+2 : nx+1) - ny;
|
|
for (i = 0;i < j;i++) zds[i] = zds[i+ny];
|
|
div.len = i;
|
|
return bigint_norm(div);
|
|
}
|
|
|
|
function bigint_div(x, y)
|
|
{
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
return bigint_divmod(x, y, 0);
|
|
}
|
|
|
|
function bigint_mod(x, y)
|
|
{
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
return bigint_divmod(x, y, 1);
|
|
}
|
|
|
|
function bigint_cmp(x, y)
|
|
{
|
|
var xlen;
|
|
|
|
if(x == y)
|
|
return 0; // Same object
|
|
|
|
x = bigint_from_any(x);
|
|
y = bigint_from_any(y);
|
|
xlen = x.len;
|
|
|
|
if(x.sign != y.sign) {
|
|
if(x.sign)
|
|
return 1;
|
|
return -1;
|
|
}
|
|
|
|
if (xlen < y.len)
|
|
return (x.sign) ? -1 : 1;
|
|
if (xlen > y.len)
|
|
return (x.sign) ? 1 : -1;
|
|
|
|
while(xlen-- && (x.digits[xlen] == y.digits[xlen]))
|
|
;
|
|
if (-1 == xlen)
|
|
return 0;
|
|
return (x.digits[xlen] > y.digits[xlen]) ?
|
|
(x.sign ? 1 : -1) :
|
|
(x.sign ? -1 : 1);
|
|
}
|
|
|
|
function bigint_number(x)
|
|
{
|
|
var d = 0.0;
|
|
var i = x.len;
|
|
var ds = x.digits;
|
|
|
|
while (i--) {
|
|
d = ds[i] + 65536.0 * d;
|
|
}
|
|
if (!x.sign) d = -d;
|
|
return d;
|
|
} |