2011-12-03 14 views
8

Quería saber cómo puedo generar pi en el enésimo dígito. Tengo un par de ideas básicas.generación pi a nth dígito java

  1. Uso Math.PI y aumentar la precisión (si eso es posible), la fórmula
  2. Uso de Euler para generar pi, pero incluso en este caso, yo tendría que aumentar la precisión (creo) Euler's formula for PI
  3. Existe también Srinivasa La fórmula de Ramanujan para generar PI, conocida por su rápida convergencia. Esta fórmula parece difícil de implementar. Creo que también debería aumentar la precisión deicómica aquí.
    enter image description here

Así que en resumen, de cualquier manera, tendría que aumentar la precisión de BigDecimal dependiendo de lo que el dígito enésimo es. ¿Cómo voy a aumentar la precisión de BigDecimal hasta el n-ésimo dígito? Además, si hay una manera mejor y más rápida de hacerlo, ¿puede indicarme 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 de generación de PI.

+0

es lo que realmente necesita para generar Pi o lo necesita para los cálculos? –

+0

¿Es esta una pregunta sobre las matemáticas detrás de la computación pi, o sobre cómo usar 'BigDecimal'? –

+0

Solo estoy usando BigDecimal para implementar las fórmulas PI y no necesito calcular PI, solo quiero generarlo. –

Respuesta

6
  • Math.PI es de tipo double. Eso significa aproximadamente 15 dígitos decimales de precisión, y esa es toda la información que tiene; nada mágicamente hará aparecer dígitos adicionales de PI.
  • BigDecimal tiene una precisión arbitraria. setScale() le permite crear objetos BigDecimal 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 irónicamente será el sqrt (2) en el factor constante, porque no hay incorporado sqrt() para BigDecimal, por lo que tendrá que escribir el suyo.
+0

Pero para la raíz cuadrada, el buen método Heron antiguo converge lo suficientemente rápido incluso con un millón (o un billón) de dígitos de precisión. –

+0

para la parte sqrt (2), ¿no puedo usar el valor predefinido? 1.41421356, ¿o eso cambiará el cálculo de alguna manera? –

+0

@ user681159: bueno, tan pronto como desee que su valor de PI sea más preciso que ese "valor predefinido", necesitará más dígitos de sqrt (2). –

3

Es necesario utilizar MathContext para aumentar la precisión de la BigDecimal

por ejemplo,

MathContext mc = new MathContext(1000); 
BigDecimal TWO = new BigDecimal(2, mc); 

Es importante que todos los BigDecimal s que utiliza en sus cálculos utilizan que 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, cree todos los BigDecimal constantes como, por ejemplo, 26390 solo una vez al inicio de su programa.

+0

¿Qué quiere decir con el método de Heron? –

+0

@ user681159 El método de Heron coincide con el método de Newton-Raphson para el caso de las raíces cuadradas, en caso de que esté familiarizado con este último. De lo contrario: está encontrando mejores aproximaciones a 'sqrt (a)' a través de 'x_ (n + 1) = 1/2 * (x_n + a/x_n)'. Convierte para todos 'a> 0' y cualquier valor inicial' x_0> 0'. Si comienza con una aproximación bastante buena, en cada paso el número de dígitos correctos se duplica (aproximadamente). –

0

Usted puede utilizar 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; 
} 
} 

resource

+0

Hay un problema con este código que conduce a un ciclo infinito bajo ciertas condiciones ;-( –