Generando pi a enésimo dígito Java
-
27-10-2019 - |
Pregunta
Quería saber cómo puedo generar PI para el enésimo dígito. Tengo un par de ideas básicas.
- Usar
Math.PI
y aumentar la precisión (si es posible) - Use la fórmula de Euler para generar PI, pero incluso aquí, necesitaría aumentar la precisión (creo)
- También está la fórmula de Srinivasa Ramanujan para generar PI que es conocida por su rápida convergencia. Esta fórmula parece difícil de implementar. Creo que también tendría que aumentar la precisión deicmal aquí.
Entonces, en resumen, de cualquier manera, necesitaría aumentar la precisión de BigDecimal
dependiendo de cuál sea el enésimo dígito. ¿Cómo haría para aumentar la precisión de BigDecimal
a enésimo dígito? Además, si hay un mejor y más rápido de hacer esto, ¿puedes señalarme en la dirección correcta?
Editar: solo quiero generar Pi. No quiero usar para los cálculos. Y esta es una pregunta sobre cómo puedo usar BigDecimal para implementar mis ideas para generar PI.
Solución
Math.PI
es de tipodouble
. Eso significa alrededor de 15 dígitos decimales de precisión, y esos son todos los datos que tiene; Nada hará que aparezcan mágicamente dígitos adicionales de Pi.BigDecimal
tiene precisión arbitraria.setScale()
te permite crearBigDecimal
Los objetos con tanta precisión como desee y la mayoría de los métodos aritméticos aumentarán automáticamente la precisión según sea necesario, pero, por supuesto, cuanto más precisión, más lentos serán todos los cálculos.- La parte más difícil de implementar la fórmula de Ramanujan será irónicamente el sqrt (2) en el factor constante, porque no hay sqrt () incorporado para
BigDecimal
, entonces tendrás que escribir el tuyo.
Otros consejos
Necesitas usar MathContext
para aumentar la precisión del BigDecimal
p.ej
MathContext mc = new MathContext(1000);
BigDecimal TWO = new BigDecimal(2, mc);
Es importante que todos los BigDecimal
S Usas en tus cálculos usa eso MathContext
. El método de Heron debería darle una precisión de 1000 dígitos con solo 10 iteraciones y un millón de dígitos con 20 iteraciones, por lo que ciertamente es lo suficientemente bueno. Además, crea toda la constante BigDecimal
s como eg 26390
Solo una vez al comienzo de su programa.
Puedes usar este código
import java.math.BigDecimal;
import java.math.RoundingMode;
public final class Pi {
private static final BigDecimal TWO = new BigDecimal("2");
private static final BigDecimal FOUR = new BigDecimal("4");
private static final BigDecimal FIVE = new BigDecimal("5");
private static final BigDecimal TWO_THIRTY_NINE = new BigDecimal("239");
private Pi() {}
public static BigDecimal pi(int numDigits) {
int calcDigits = numDigits + 10;
return FOUR.multiply((FOUR.multiply(arccot(FIVE, calcDigits)))
.subtract(arccot(TWO_THIRTY_NINE, calcDigits)))
.setScale(numDigits, RoundingMode.DOWN);
}
private static BigDecimal arccot(BigDecimal x, int numDigits) {
BigDecimal unity = BigDecimal.ONE.setScale(numDigits,
RoundingMode.DOWN);
BigDecimal sum = unity.divide(x, RoundingMode.DOWN);
BigDecimal xpower = new BigDecimal(sum.toString());
BigDecimal term = null;
boolean add = false;
for (BigDecimal n = new BigDecimal("3"); term == null ||
term.compareTo(BigDecimal.ZERO) != 0; n = n.add(TWO)) {
xpower = xpower.divide(x.pow(2), RoundingMode.DOWN);
term = xpower.divide(n, RoundingMode.DOWN);
sum = add ? sum.add(term) : sum.subtract(term);
add = ! add;
}
return sum;
}
}