Skip to content

Instantly share code, notes, and snippets.

@edvakf
Created April 30, 2011 09:13
Show Gist options
  • Select an option

  • Save edvakf/949546 to your computer and use it in GitHub Desktop.

Select an option

Save edvakf/949546 to your computer and use it in GitHub Desktop.
var bigint;
// very very basic bigint class.
// complete version: https://github.com/dankogai/js-math-bigint
(function() {
// Original: http://www.onicos.com/staff/iz/amuse/javascript/expert/BigInt.txt
//
// BigInt.js - Arbitrary size integer math package for JavaScript
// Copyright (C) 2000 Masanao Izumo <iz@onicos.co.jp>
// Copyright (C) 2010 Dan Kogai <dankogai+404bnf@gmail.com>
// 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.
//
// bigint_sub_internal was buggy so rewritten.
function _BigInt_toString() {
return this.toStringBase(10);
}
function _BigInt_toStringBase(base) {
var i, j, hbase, t, ds, 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, 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 i, l, x = new BigInt(this.len, this.sign);
for (i = 0, l = this.len; i < l; 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.
if (arguments.length === 0) {
this.sign = true;
this.len = len = 1;
this.digits = new Array(1);
need_init = true;
} else if (arguments.length === 1) {
x = bigint_from_any(arguments[0]);
if (x === 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, 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;
}
var bzero = bigint_from_int(0);
function bigint_from_string(str, base) {
var str_i, sign = true, c, len, z, zds, num, i, 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') {
return (x instanceof BigInt) ? x : bzero;
}
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);
}
/*
* By Dan Kogai
*/
BigInt.prototype = {
toString: _BigInt_toString,
toStringBase: _BigInt_toStringBase,
clone: _BigInt_clone,
};
Math.BigInt = BigInt;
bigint = function(a) { return bigint_from_any(a) };
})();
var BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
function binaryToBase64(bin) {
var base = [];
for (var i = 0, l = bin.length; i < l; ) {
var n = (bin[i++] << 0) // converts undefined to zero
+ (bin[i++] << 1)
+ (bin[i++] << 2)
+ (bin[i++] << 3)
+ (bin[i++] << 4)
+ (bin[i++] << 5);
base.push(BASE64.charAt(n));
}
return base.join('');
}
function base64ToBinary(b64) {
var bin = [];
for (var i = 0, l = b64.length; i < l; i++) {
var n = BASE64.indexOf(b64.charAt(i));
bin.push(n % 2,
(n >> 1) % 2,
(n >> 2) % 2,
(n >> 3) % 2,
(n >> 4) % 2,
(n >> 5) % 2);
}
while (bin[bin.length - 1] === 0) {
bin.pop();
}
return bin;
}
var x = bigint("64098252294864896"); // new id (56 bit)
//var x = bigint("25033162086"); // old id (35 bit)
var x2 = x.toStringBase(2);
print(x2);
if (x2.length === 56 && x2.slice(-8) === '00000000') {
// last 8 bits are usually all zero. in that case, remove them
var ba = binaryToBase64(x2.split('').slice(0, -8).reverse());
} else {
var ba = binaryToBase64(x2.split('').reverse());
}
print(ba);
var bi = base64ToBinary(ba).reverse().join('');
print(bi);
if (bi.length === 48) {
bi += '00000000';
}
print(bi);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment