# How to calculate PI with "n" decimal places in JavaScript?

17

Using the `Math` object of JavaScript, I can return a PI value with fixed decimal places, for example:

``````Math.PI //3.141592653589793
``````

But in case I need (yes, quite unusual) to calculate the same with more decimal places, is there any other way to define a number of decimal places? Example:

``````Math.pi(300) //retornaria com precisão de 300 casas decimais, etc.
``````

asked by anonymous 22.02.2015 / 22:38

24

The first thing you need is a library of arbitrary precision decimal numbers. A `double` (numeric format used by JavaScript for type `Number` ) is accurate to a maximum of 15 decimal places ( `floor(log10(2^53))` ), so if you need to make any account involving more houses than this, these numbers in some other way.

(and you want to be accountable for π, right? Well, if it were just a matter of displaying it, a pre-populated string with its value would suffice ...)

Once you have chosen a library, you have two options:

• To be used in practice, it is preferable to get the value of π from somewhere instead of calculating it from π- it. A 300-byte string does not bring such a great overhead to your system ... (especially the extra code you would have to put in to do your calculation)
• If it is really necessary (or desirable, for example for study purposes) to calculate for yourself, there are several formulas that converge to π. One of them (the first suggestion of the bigown answer ) is `π = 48*arctan(1/18) + 32*arctan(1/57) − 20*arctan(1/239)` , where the tangent arc can be calculated by middle of an infinite series. Other infinite series and / or expressions also converge to π.
• I do not know which is the best (nor which is the best criterion to define "the best"), so I'll give you an example using the sine, as it seems very easy to calculate:

``````                1 * x^3   1 * 3 * x^5   1 * 3 * 5 * x^7
arcsin(x) = x + ------- + ----------- + --------------- + ...
2 * 3     2 * 4 * 5     2 * 4 * 6 * 7

arcsin(1/2) = π/6
``````

Using the javascript-bignum library:

``````var pi = new BigNumber("3", precisao + 5); // Começa com 3 (6*x, x == 1/2)
var antigo = new BigNumber("0", precisao + 5);

var numerador = new BigNumber("6", precisao + 5); // O numerador da próxima parcela
var denominador = new BigNumber("1", precisao + 5); // Parte do denominador (comum)
var potencia2 = new BigNumber("2", precisao + 5); // Outra parte (variável)

var indice = 1; // Qual parcela está sendo acrescentada

function passo() {
if ( pi.compare(antigo) == 0 ) // Se o valor não mudou, já convergiu
return;

antigo = pi; // Salva o valor antigo

potencia2 = potencia2.multiply(4);

// Acrescenta a próxima parcela na série

indice += 2
setTimeout(passo, 0); // Executa o próximo passo (assíncrono)
}
passo(); // Começa
``````

``````//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/bignumber [rev. #4]

BigNumber = function(n, p, r){
var o = this, i;
if(n instanceof BigNumber){
for(i in {precision: 0, roundType: 0, _s: 0, _f: 0}) o[i] = n[i];
o._d = n._d.slice();
return;
}
o.precision = isNaN(p = Math.abs(p)) ? BigNumber.defaultPrecision : p;
o.roundType = isNaN(r = Math.abs(r)) ? BigNumber.defaultRoundType : r;
o._s = (n += "").charAt(0) == "-";
o._f = ((n = n.replace(/[^\d.]/g, "").split(".", 2))[0] = n[0].replace(/^0+/, "") || "0").length;
for(i = (n = o._d = (n.join("") || "0").split("")).length; i; n[--i] = +n[i]);
o.round();
};
with({\$: BigNumber, o: BigNumber.prototype}){
\$.ROUND_HALF_EVEN = (\$.ROUND_HALF_DOWN = (\$.ROUND_HALF_UP = (\$.ROUND_FLOOR = (\$.ROUND_CEIL = (\$.ROUND_DOWN = (\$.ROUND_UP = 0) + 1) + 1) + 1) + 1) + 1) + 1;
\$.defaultPrecision = 40;
\$.defaultRoundType = \$.ROUND_HALF_UP;
if(this._s != (n = new BigNumber(n))._s)
return n._s ^= 1, this.subtract(n);
var o = new BigNumber(this), a = o._d, b = n._d, la = o._f,
lb = n._f, n = Math.max(la, lb), i, r;
la != lb && ((lb = la - lb) > 0 ? o._zeroes(b, lb, 1) : o._zeroes(a, -lb, 1));
i = (la = a.length) == (lb = b.length) ? a.length : ((lb = la - lb) > 0 ? o._zeroes(b, lb) : o._zeroes(a, -lb)).length;
for(r = 0; i; r = (a[--i] = a[i] + b[i] + r) / 10 >>> 0, a[i] %= 10);
return r && ++n && a.unshift(r), o._f = n, o.round();
};
o.subtract = function(n){
if(this._s != (n = new BigNumber(n))._s)
var o = new BigNumber(this), c = o.abs().compare(n.abs()) + 1, a = c ? o : n, b = c ? n : o, la = a._f, lb = b._f, d = la, i, j;
a = a._d, b = b._d, la != lb && ((lb = la - lb) > 0 ? o._zeroes(b, lb, 1) : o._zeroes(a, -lb, 1));
for(i = (la = a.length) == (lb = b.length) ? a.length : ((lb = la - lb) > 0 ? o._zeroes(b, lb) : o._zeroes(a, -lb)).length; i;){
if(a[--i] < b[i]){
for(j = i; j && !a[--j]; a[j] = 9);
--a[j], a[i] += 10;
}
b[i] = a[i] - b[i];
}
return c || (o._s ^= 1), o._f = d, o._d = b, o.round();
};
o.multiply = function(n){
var o = new BigNumber(this), r = o._d.length >= (n = new BigNumber(n))._d.length, a = (r ? o : n)._d,
b = (r ? n : o)._d, la = a.length, lb = b.length, x = new BigNumber, i, j, s;
for(i = lb; i; r && s.unshift(r), x.set(x.add(new BigNumber(s.join("")))))
for(s = (new Array(lb - --i)).join("0").split(""), r = 0, j = la; j; r += a[--j] * b[i], s.unshift(r % 10), r = (r / 10) >>> 0);
return o._s = o._s != n._s, o._f = ((r = la + lb - o._f - n._f) >= (j = (o._d = x._d).length) ? this._zeroes(o._d, r - j + 1, 1).length : j) - r, o.round();
};
o.divide = function(n){
if((n = new BigNumber(n)) == "0")
throw new Error("Division by 0");
else if(this == "0")
return new BigNumber;
var o = new BigNumber(this), a = o._d, b = n._d, la = a.length - o._f,
lb = b.length - n._f, r = new BigNumber, i = 0, j, s, l, f = 1, c = 0, e = 0;
r._s = o._s != n._s, r.precision = Math.max(o.precision, n.precision),
r._f = +r._d.pop(), la != lb && o._zeroes(la > lb ? b : a, Math.abs(la - lb));
n._f = b.length, b = n, b._s = false, b = b.round();
for(n = new BigNumber; a[0] == "0"; a.shift());
out:
do{
for(l = c = 0, n == "0" && (n._d = [], n._f = 0); i < a.length && n.compare(b) == -1; ++i){
(l = i + 1 == a.length, (!f && ++c > 1 || (e = l && n == "0" && a[i] == "0")))
&& (r._f == r._d.length && ++r._f, r._d.push(0));
(a[i] == "0" && n == "0") || (n._d.push(a[i]), ++n._f);
if(e)
break out;
if((l && n.compare(b) == -1 && (r._f == r._d.length && ++r._f, 1)) || (l = 0))
while(r._d.push(0), n._d.push(0), ++n._f, n.compare(b) == -1);
}
if(f = 0, n.compare(b) == -1 && !(l = 0))
while(l ? r._d.push(0) : l = 1, n._d.push(0), ++n._f, n.compare(b) == -1);
for(s = new BigNumber, j = 0; n.compare(y = s.add(b)) + 1 && ++j; s.set(y));
n.set(n.subtract(s)), !l && r._f == r._d.length && ++r._f, r._d.push(j);
}
while((i < a.length || n != "0") && (r._d.length - r._f) <= r.precision);
return r.round();
};
o.mod = function(n){
return this.subtract(this.divide(n).intPart().multiply(n));
};
o.pow = function(n){
var o = new BigNumber(this), i;
if((n = (new BigNumber(n)).intPart()) == 0) return o.set(1);
for(i = Math.abs(n); --i; o.set(o.multiply(this)));
return n < 0 ? o.set((new BigNumber(1)).divide(o)) : o;
};
o.set = function(n){
return this.constructor(n), this;
};
o.compare = function(n){
var a = this, la = this._f, b = new BigNumber(n), lb = b._f, r = [-1, 1], i, l;
if(a._s != b._s)
return a._s ? -1 : 1;
if(la != lb)
return r[(la > lb) ^ a._s];
for(la = (a = a._d).length, lb = (b = b._d).length, i = -1, l = Math.min(la, lb); ++i < l;)
if(a[i] != b[i])
return r[(a[i] > b[i]) ^ a._s];
return la != lb ? r[(la > lb) ^ a._s] : 0;
};
o.negate = function(){
var n = new BigNumber(this); return n._s ^= 1, n;
};
o.abs = function(){
var n = new BigNumber(this); return n._s = 0, n;
};
o.intPart = function(){
return new BigNumber((this._s ? "-" : "") + (this._d.slice(0, this._f).join("") || "0"));
};
o.valueOf = o.toString = function(){
var o = this;
return (o._s ? "-" : "") + (o._d.slice(0, o._f).join("") || "0") + (o._f != o._d.length ? "." + o._d.slice(o._f).join("") : "");
};
o._zeroes = function(n, l, t){
var s = ["push", "unshift"][t || 0];
for(++l; --l;  n[s](0));
return n;
};
o.round = function(){
if("_rounding" in this) return this;
var \$ = BigNumber, r = this.roundType, b = this._d, d, p, n, x;
for(this._rounding = true; this._f > 1 && !b[0]; --this._f, b.shift());
for(d = this._f, p = this.precision + d, n = b[p]; b.length > d && !b[b.length -1]; b.pop());
x = (this._s ? "-" : "") + (p - d ? "0." + this._zeroes([], p - d - 1).join("") : "") + 1;
if(b.length > p){
n && (r == \$.DOWN ? false : r == \$.UP ? true : r == \$.CEIL ? !this._s
: r == \$.FLOOR ? this._s : r == \$.HALF_UP ? n >= 5 : r == \$.HALF_DOWN ? n > 5
: r == \$.HALF_EVEN ? n >= 5 && b[p - 1] & 1 : false) && this.add(x);
b.splice(p, b.length - p);
}
return delete this._rounding, this;
};
}

var continuar = true;
document.getElementById("calcular").onclick = function() {
var precisao = parseInt(document.getElementById("precisao").value, 10);

var pi = new BigNumber("3", precisao + 5);
var antigo = new BigNumber("0", precisao + 5);

var numerador = new BigNumber("6", precisao + 5);
var denominador = new BigNumber("1", precisao + 5);
var potencia2 = new BigNumber("2", precisao + 5);

var indice = 1;
function passo() {
if ( pi.compare(antigo) == 0 || !continuar )
return;

antigo = pi;

potencia2 = potencia2.multiply(4);

indice += 2
atualizar();

setTimeout(passo, 0);
}

continuar = true;
passo();

function atualizar() {
var str1 = "" + pi;
var str2 = "" + antigo;
var saida = "<strong>";
var igual = true;
for ( var i = 0 ; i < precisao ; i++ ) {
if ( igual && str1[i] != str2[i] ) {
igual = false;
saida += "</strong>"
}
saida += str1[i];
}
document.getElementById("saida").innerHTML = saida;
}
};

document.getElementById("parar").onclick = function() {
continuar = false;
};``````
``````Precisão: <input id="precisao" type="number" value="70"/>
<button id="calcular">Calcular</button>
<button id="parar">Parar</button>
<p id="saida"></p>``````

In the code example above, `precisao + 5` is to give a reasonable margin for convergence to occur (otherwise, smaller portions will be rounded to zero and will not enter the series). I put 70 decimal places, because it takes a lot to converge in the case of 300 (if you have the patience to wait, it should work, though).

23.02.2015 / 05:01
6

Surely you would have to create your own algorithm and it is not that simple.

I found this code . As there is no explicit license, I do not know if I can bring it here.

Another code that I can maybe use as a reference.

If I find anything else that can improve the answer I'll post it here.

22.02.2015 / 22:45
0

# Pi One-liner

Below some one-liner using several languages ... (almost all stolen! from various sources)

(bc = unix calculator) ( `tang(π/4)=1` therefore `4 x arcotang(1)= 4 x π/4= π` )

``````bc -l <<< "scale=1000; 4*a(1)"
``````

internet -based ...

``````curl --silent http://www.angio.net/pi/digits/pi1000000.txt | cut -c1-3000
``````

perl

``````perl -Mbignum=bpi -le 'print bpi(100)'
``````

python

``````python -c "from mpmath import mp;mp.dps=500;print mp.pi"
``````

I'm sure some include will have the PI with some houses ...

``````grep -ohP '3.14\d{30,}' /usr/include/*.h
``````

or even choose the most complete PI of includes

``````grep -rohP '3\.14\d*' /usr/include | awk 'length > length(pi){pi=\$0}  END{print pi}'
3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651
``````

``````tex --version | head -1 | cut -f2 -d' '