pasm
Version:
Piston X86-64 Assembler
727 lines (619 loc) • 15.9 kB
HTML
<html>
<head><title>Pi calculator</title>
<embed type="application/x-gmplib" id="lib" width="0" height="0">
<script>
// Translation of gmp-chudnovsky.c by John Tobey.
function onload() {
lib = document.getElementById("lib");
arg = document.getElementById("arg");
result = document.getElementById("result");
fn = (function() {
var
sqrt = Math.sqrt,
min = Math.min,
max = Math.max,
mpf = lib.mpf,
mpf_init = mpf.init,
mpf_get_prec = mpf.get_prec,
mpf_set_d = mpf.set_d,
mpf_set_prec_raw = mpf.set_prec_raw,
mpf_mul = mpf.mul,
mpf_mul_ui = mpf.mul_ui,
mpf_ui_sub = mpf.ui_sub,
mpf_div_2exp = mpf.div_2exp,
my_div = mpf.div,
mpf_add = mpf.add,
mpz = lib.mpz,
mpz_set_ui = mpz.set_ui,
mpz_mul_ui = mpz.mul_ui,
mpz_add_ui = mpz.add_ui,
mpz_mul = mpz.mul,
mpz_neg = mpz.neg,
mpz_add = mpz.add,
mpz_divexact = mpz.divexact,
mpz_clear = mpz.clear,
mpf_set_default_prec= mpf.set_default_prec,
mpz_sizeinbase = mpz.sizeinbase,
mpz_addmul_ui = mpz.addmul_ui,
mpf_set_z = mpf.set_z;
/* Pi computation using Chudnovsky's algortithm.
* Copyright 2002, 2005 Hanhong Xue (macroxue at yahoo dot com)
* Slightly modified 2005 by Torbjorn Granlund to allow more than 2G
digits to be computed.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var A = 13591409;
var B = 545140134;
var C = 640320;
var D = 12;
var BITS_PER_DIGIT = 3.32192809488736234787;
var DIGITS_PER_ITER = 14.1816474627254776555;
var DOUBLE_PREC = 53;
var t1 = mpf(), t2 = mpf();
/* r = sqrt(x) */
function my_sqrt_ui(r, x)
{
var prec, bits, prec0;
prec0 = mpf_get_prec(r);
if (prec0<=DOUBLE_PREC) {
mpf_set_d(r, sqrt(x));
return;
}
bits = 0;
for (prec=prec0; prec>DOUBLE_PREC;)
{
var bit = prec&1;
prec = (prec+bit)>>1;
bits = bits*2+bit;
}
mpf_set_prec_raw(t1, DOUBLE_PREC);
mpf_set_d(t1, 1/sqrt(x));
while (prec<prec0)
{
prec *=2;
if (prec<prec0)
{
/* t1 = t1+t1*(1-x*t1*t1)/2; */
mpf_set_prec_raw(t2, prec);
mpf_mul(t2, t1, t1); /* half x half -> full */
mpf_mul_ui(t2, t2, x);
mpf_ui_sub(t2, 1, t2);
mpf_set_prec_raw(t2, prec>>1);
mpf_div_2exp(t2, t2, 1);
mpf_mul(t2, t2, t1); /* half x half -> half */
mpf_set_prec_raw(t1, prec);
mpf_add(t1, t1, t2);
}
else
{
break;
}
prec -= (bits&1);
bits /=2;
}
/* t2=x*t1, t1 = t2+t1*(x-t2*t2)/2; */
mpf_set_prec_raw(t2, prec0>>1);
mpf_mul_ui(t2, t1, x);
mpf_mul(r, t2, t2); /* half x half -> full */
mpf_ui_sub(r, x, r);
mpf_mul(t1, t1, r); /* half x half -> half */
mpf_div_2exp(t1, t1, 1);
mpf_add(r, t1, t2);
}
var sieve = [];
var sieve_size;
var ftmp = {}, fmul = {};
var INIT_FACS = 32;
function fac_toString(f)
{
var i, ret = "";
for (i=0; i<f.num_facs; i++)
if (f.pow[i]==1)
ret += f.fac[i] + " ";
else
ret += f.fac[i] + "^" + f.pow[i] + " ";
return ret;
}
function fac_show(f) { my_log(fac_toString(f)); }
function fac_reset(f)
{
f.num_facs = 0;
}
function fac_init_size(f, s)
{
if (s<INIT_FACS)
s=INIT_FACS;
f.fac = Array(s);
f.pow = Array(s);
f.max_facs = s;
fac_reset(f);
}
function fac_init(f)
{
fac_init_size(f, INIT_FACS);
}
function fac() {
var ret = {};
fac_init(ret);
return ret;
}
function fac_clear(f)
{
delete f.fac;
delete f.pow;
}
function fac_resize(f, s)
{
if (f.max_facs < s) {
fac_clear(f);
fac_init_size(f, s);
}
}
/* f = base^pow */
function fac_set_bp(f, base, pow)
{
var i;
//assert(base<sieve_size);
for (i=0, base>>=1; base>0; i++, base = sieve[base].nxt) {
f.fac[i] = sieve[base].fac;
f.pow[i] = sieve[base].pow*pow;
}
f.num_facs = i;
//assert(i<=f.max_facs);
}
/* r = f*g */
function fac_mul2(r, f, g)
{
var i, j, k;
for (i=j=k=0; i<f.num_facs && j<g.num_facs; k++) {
if (f.fac[i] == g.fac[j]) {
r.fac[k] = f.fac[i];
r.pow[k] = f.pow[i] + g.pow[j];
i++; j++;
} else if (f.fac[i] < g.fac[j]) {
r.fac[k] = f.fac[i];
r.pow[k] = f.pow[i];
i++;
} else {
r.fac[k] = g.fac[j];
r.pow[k] = g.pow[j];
j++;
}
}
for (; i<f.num_facs; i++, k++) {
r.fac[k] = f.fac[i];
r.pow[k] = f.pow[i];
}
for (; j<g.num_facs; j++, k++) {
r.fac[k] = g.fac[j];
r.pow[k] = g.pow[j];
}
r.num_facs = k;
//assert(k<=r.max_facs);
}
/* r = f */
function fac_set(r, f)
{
r.num_facs = f.num_facs;
r.max_facs = f.max_facs;
r.fac = f.fac;
r.pow = f.pow;
}
/* f *= g */
function fac_mul(f, g)
{
var tmp = fac();
fac_resize(fmul, f.num_facs + g.num_facs);
fac_mul2(fmul, f, g);
fac_set(tmp, f);
fac_set(f, fmul);
fac_set(fmul, tmp);
}
/* f *= base^pow */
function fac_mul_bp(f, base, pow)
{
fac_set_bp(ftmp, base, pow);
fac_mul(f, ftmp);
}
/* remove factors of power 0 */
function fac_compact(f)
{
var i, j;
for (i=0, j=0; i<f.num_facs; i++) {
if (f.pow[i]>0) {
if (j<i) {
f.fac[j] = f.fac[i];
f.pow[j] = f.pow[i];
}
j++;
}
}
f.num_facs = j;
}
/* convert factorized form to number */
function bs_mul(r, a, b)
{
var i, j;
if (b-a<=32) {
mpz_set_ui(r, 1);
for (i=a; i<b; i++)
for (j=0; j<fmul.pow[i]; j++)
mpz_mul_ui(r, r, fmul.fac[i]);
} else {
var r2 = mpz();
//mpz_init(r2);
bs_mul(r2, a, (a+b)>>1);
bs_mul(r, (a+b)>>1, b);
mpz_mul(r, r, r2);
//mpz_clear(r2);
}
}
var gcd = mpz(), mgcd = mpz();
/* f /= gcd(f,g), g /= gcd(f,g) */
function fac_remove_gcd(p, fp, g, fg)
{
var i, j, k, c;
fac_resize(fmul, min(fp.num_facs, fg.num_facs));
for (i=j=k=0; i<fp.num_facs && j<fg.num_facs; ) {
if (fp.fac[i] == fg.fac[j]) {
c = min(fp.pow[i], fg.pow[j]);
fp.pow[i] -= c;
fg.pow[j] -= c;
fmul.fac[k] = fp.fac[i];
fmul.pow[k] = c;
i++; j++; k++;
} else if (fp.fac[i] < fg.fac[j]) {
i++;
} else {
j++;
}
}
fmul.num_facs = k;
//assert(k <= fmul.max_facs);
if (fmul.num_facs) {
bs_mul(gcd, 0, fmul.num_facs);
mpz_divexact(p, p, gcd);
mpz_divexact(g, g, gcd);
fac_compact(fp);
fac_compact(fg);
}
}
/*///////////////////////////////////////////////////////////////////////////*/
var out=0;
var pstack=[], qstack=[], gstack=[];
var fpstack=[], fgstack=[];
var top = 0;
var progress=0, percent;
/* binary splitting */
function bs(a, b, gflag, level)
{
var i, mid;
var ccc;
var p1 = pstack[top];
var q1 = qstack[top];
var g1 = gstack[top];
var fp1 = fpstack[top];
var fg1 = fgstack[top];
var p2 = pstack[top+1];
var q2 = qstack[top+1];
var g2 = gstack[top+1];
var fp2 = fpstack[top+1];
var fg2 = fgstack[top+1];
if (b-a==1) {
/*
g(b-1,b) = (6b-5)(2b-1)(6b-1)
p(b-1,b) = b^3 * C^3 / 24
q(b-1,b) = (-1)^b*g(b-1,b)*(A+Bb).
*/
mpz_set_ui(p1, b);
mpz_mul_ui(p1, p1, b);
mpz_mul_ui(p1, p1, b);
mpz_mul_ui(p1, p1, Math.floor(C/24)*Math.floor(C/24));
mpz_mul_ui(p1, p1, Math.floor(C*24));
mpz_set_ui(g1, 2*b-1);
mpz_mul_ui(g1, g1, 6*b-1);
mpz_mul_ui(g1, g1, 6*b-5);
mpz_set_ui(q1, b);
mpz_mul_ui(q1, q1, B);
mpz_add_ui(q1, q1, A);
mpz_mul (q1, q1, g1);
if (b%2)
mpz_neg(q1, q1);
i=b;
while ((i&1)==0) i>>=1;
fac_set_bp(fp1, i, 3); /* b^3 */
fac_mul_bp(fp1, 3*5*23*29, 3);
fp1.pow[0]--;
fac_set_bp(fg1, 2*b-1, 1); /* 2b-1 */
fac_mul_bp(fg1, 6*b-1, 1); /* 6b-1 */
fac_mul_bp(fg1, 6*b-5, 1); /* 6b-5 */
if (b>progress) {
//printf("."); fflush(stdout);
progress += percent*2;
}
} else {
/*
p(a,b) = p(a,m) * p(m,b)
g(a,b) = g(a,m) * g(m,b)
q(a,b) = q(a,m) * p(m,b) + q(m,b) * g(a,m)
*/
mid = Math.floor(a+(b-a)*0.5224); /* tuning parameter */
bs(a, mid, 1, level+1);
top++;
bs(mid, b, gflag, level+1);
top--;
//if (level == 0)
//puts ("");
ccc = level == 0;
//if (ccc) CHECK_MEMUSAGE;
if (level>=4) { /* tuning parameter */
fac_remove_gcd(p2, fp2, g1, fg1);
}
//if (ccc) CHECK_MEMUSAGE;
mpz_mul(p1, p1, p2);
//if (ccc) CHECK_MEMUSAGE;
mpz_mul(q1, q1, p2);
//if (ccc) CHECK_MEMUSAGE;
mpz_mul(q2, q2, g1);
//if (ccc) CHECK_MEMUSAGE;
mpz_add(q1, q1, q2);
//if (ccc) CHECK_MEMUSAGE;
fac_mul(fp1, fp2);
if (gflag) {
mpz_mul(g1, g1, g2);
fac_mul(fg1, fg2);
}
}
if (out&2) {
my_log("p(" + a + "," + b + ")=" + fac_toString(fp1));
if (gflag)
my_log("g(" + a + "," + b + ")=" + fac_toString(fg1));
}
}
function build_sieve(n, s)
{
var m, i, j, k;
sieve_size = n;
m = Math.floor(sqrt(n));
for (i = 0; i < n>>1; i++)
s[i] = { fac: 0, pow: 0, nxt: 0 };
s[1>>1].fac = 1;
s[1>>1].pow = 1;
for (i=3; i<=n; i+=2) {
if (s[i>>1].fac == 0) {
s[i>>1].fac = i;
s[i>>1].pow = 1;
if (i<=m) {
for (j=i*i, k=i>>1; j<=n; j+=i+i, k++) {
if (s[j>>1].fac==0) {
s[j>>1].fac = i;
if (s[k].fac == i) {
s[j>>1].pow = s[k].pow + 1;
s[j>>1].nxt = s[k].nxt;
} else {
s[j>>1].pow = 1;
s[j>>1].nxt = k;
}
}
}
}
}
}
}
function main(d, outval)
{
var pi = mpf(), qi = mpf();
d = d || 100;
out = outval || 0;
var i, depth=1, terms;
var psize, qsize;
var begin, mid0, mid1, mid2, mid3, mid4, end;
terms = Math.floor(d/DIGITS_PER_ITER);
while ((1<<depth)<terms)
depth++;
depth++;
percent = terms/100.0;
//printf("#terms=%ld, depth=%ld\n", terms, depth);
//begin = cputime();
//printf("sieve "); fflush(stdout);
sieve_size = max(3*5*23*29+1, terms*6);
sieve = Array(sieve_size>>1);
build_sieve(sieve_size, sieve);
//mid0 = cputime();
//printf("time = %6.3f\n", (double)(mid0-begin)/1000);
/* allocate stacks */
pstack = Array(depth);
qstack = Array(depth);
gstack = Array(depth);
fpstack = Array(depth);
fgstack = Array(depth);
for (i=0; i<depth; i++) {
pstack[i] = mpz();
qstack[i] = mpz();
gstack[i] = mpz();
fpstack[i] = fac();
fgstack[i] = fac();
}
fac_init(ftmp);
fac_init(fmul);
var p1 = pstack[top];
var q1 = qstack[top];
var g1 = gstack[top];
var fp1 = fpstack[top];
var fg1 = fgstack[top];
var p2 = pstack[top+1];
var q2 = qstack[top+1];
var g2 = gstack[top+1];
var fp2 = fpstack[top+1];
var fg2 = fgstack[top+1];
/* begin binary splitting process */
if (terms<=0) {
mpz_set_ui(p2,1);
mpz_set_ui(q2,0);
mpz_set_ui(g2,1);
} else {
bs(0,terms,0,0);
}
/*
mid1 = cputime();
printf("\nbs time = %6.3f\n", (double)(mid1-mid0)/1000);
printf(" gcd time = %6.3f\n", (double)(gcd_time)/1000);
*/
/* printf("misc "); fflush(stdout); */
/* free some resources */
sieve = undefined;
mpz_clear(gcd);
fac_clear(ftmp);
fac_clear(fmul);
for (i=1; i<depth; i++) {
mpz_clear(pstack[i]);
mpz_clear(qstack[i]);
mpz_clear(gstack[i]);
fac_clear(fpstack[i]);
fac_clear(fgstack[i]);
}
mpz_clear(gstack[0]);
fac_clear(fpstack[0]);
fac_clear(fgstack[0]);
gstack = undefined;
fpstack = undefined;
fgstack = undefined;
/* prepare to convert integers to floats */
mpf_set_default_prec(Math.floor(d*BITS_PER_DIGIT+16));
/*
p*(C/D)*sqrt(C)
pi = -----------------
(q+A*p)
*/
psize = mpz_sizeinbase(p1,10);
qsize = mpz_sizeinbase(q1,10);
mpz_addmul_ui(q1, p1, A);
mpz_mul_ui(p1, p1, Math.floor(C/D));
mpf_init(pi);
mpf_set_z(pi, p1);
mpz_clear(p1);
mpf_init(qi);
mpf_set_z(qi, q1);
mpz_clear(q1);
pstack = undefined;
qstack = undefined;
//mid2 = cputime();
/* printf("time = %6.3f\n", (double)(mid2-mid1)/1000); */
/* initialize temp float variables for sqrt & div */
mpf_init(t1);
mpf_init(t2);
mpf_set_prec_raw(t1, mpf_get_prec(pi));
/* final step */
//printf("div "); fflush(stdout);
my_div(qi, pi, qi);
//mid3 = cputime();
//printf("time = %6.3f\n", (double)(mid3-mid2)/1000);
//printf("sqrt "); fflush(stdout);
my_sqrt_ui(pi, C);
//mid4 = cputime();
//printf("time = %6.3f\n", (double)(mid4-mid3)/1000);
//printf("mul "); fflush(stdout);
mpf_mul(qi, qi, pi);
//end = cputime();
//printf("time = %6.3f\n", (double)(end-mid4)/1000);
//printf("total time = %6.3f\n", (double)(end-begin)/1000);
//fflush(stdout);
/*
printf(" P size=%ld digits (%f)\n"
" Q size=%ld digits (%f)\n",
psize, (double)psize/d, qsize, (double)qsize/d);
*/
/* output Pi and timing statistics */
/*
if (out&1) {
printf("pi(0,%ld)=\n", terms);
mpf_out_str(stdout, 10, d+2, qi);
printf("\n");
}
*/
/* free float resources */
/*
mpf_clear(pi);
mpf_clear(qi);
mpf_clear(t1);
mpf_clear(t2);
exit (0);
*/
return qi.toString(10, d+2);
}
return main;
})();
}
function trace_all_calls(gmp) {
// Wrap every gmp function...
var ret = {};
for (var i in gmp) {
var x = gmp[i];
if (typeof x === "function" && i === i.toLowerCase()) {
x = (function (o, i, len) {
function ret(a,b,c,d,e) {
var args = Array.prototype.slice.call(arguments);
my_log(i + "(" + args.join(",") + ")");
switch (len) {
case 0: return o();
case 1: return o(a);
case 2: return o(a,b);
case 3: return o(a,b,c);
case 4: return o(a,b,c,d);
case 5: return o(a,b,c,d,e);
default: throw "length " + len;
}
}
return ret;
})(x, i, x.length + 0);
}
ret[i] = x;
}
return ret;
}
var logged = 0;
function my_log() {
console.log.apply(console.log, Array.prototype.slice.call(arguments));
logged++;
if (logged == 250) {
if (!confirm("logged a lot"))
throw Error("logged too much");
logged = 0;
}
}
function doit() {
try {
result.innerHTML = eval(arg.value);
}
catch (e) {
alert(e);
}
}
</script>
</head>
<body onload="onload()">
<form onsubmit="return false;">
<textarea id="arg" rows="20" cols="80">(function(){
// Replace 10000 with a number of digits and click the button.
return fn(10000);
})()</textarea><button onclick="doit()">=</button><span id="result"></span>
</form>
</body>
</html>