Pi todavía está equivocado [cerrado]

27

Pi está equivocado

Un método común para calcular pi es lanzar "dardos" en una caja 1x1 y ver qué tierra en el círculo de la unidad en comparación con el total arrojado:

loop
   x = rand()
   y = rand()
   if(sqrt(x*x + y*y) <= 1) n++
   t++
pi = 4.0*(n/t)

Escriba un programa que parezca que debería calcular correctamente pi (utilizando este u otros métodos comunes de cálculo de pi) pero en su lugar calcula tau (tau = 2 * pi = 6.283185307179586 ...). Su código debe producir al menos los primeros 6 decimales: 6.283185

El ganador es coronado el 6 de junio (una semana a partir de hoy).

Kyle Kanos
fuente
43
¿Por qué el ganador no es coronado el 28 de junio?
corsiKa
99
No estoy seguro de por qué un ganador necesita ser coronado en un concurso de popularidad.
Tim S.
1
No lo entiendo Esto es como pedir una función que parece regresar 1pero regresa 2. ¿A quién estamos engañando aquí?
ja72
3
@ ja72 El lector del código :)
tomsmeding
8
Todos saben que pau es el correcto . : P
Justin Krejcha 01 de

Respuestas:

57

JavaScript

alert(Math.atan2(0, -0) - Math.atan2(-0, -0) + Math.atan2(0, 0))

Ayuda, estoy atrapado en una fábrica de universos y no estoy seguro de lo que estoy haciendo. Math.atan2se supone que devuelve pi con buenos valores, ¿verdad? Math.atan2(0, -0)devuelve pi, por lo que si lo resto y lo agrego, aún debería tener pi.

Konrad Borowski
fuente
14
Creo que voy a acostarme y llorar. Maldita sea, JavaScript.
Jack M
3
explicación por favor? :)
Jaa-c
2
Ángulo en sentido antihorario en radianes entre el eje xy el punto (Y, X). El signo del punto Y determina si este es un ángulo positivo o negativo, y esto se convierte enπ - (-π)
8
0_o >>> 0 === -0 ;true ;>>> Math.atan2(0, 0) ;0 ;>>> Math.atan2(0, -0) ;3.141592653589793
Izkata 01 de
55
@JackM, esa afirmación siempre es apropiada para decir :) Aunque en este caso, se debe al estándar IEEE, y muchos idiomas (no solo JS) tienen el problema cero vs cero negativo.
Paul Draper
40

BASIC

(Más específicamente, Chipmunk Basic )

Utiliza una serie infinita descubierta por Nilakantha Somayaji en el siglo XV:

' Calculate pi using the Nilakantha series:
'               4       4       4       4
'  pi  =  3 + ----- - ----- + ----- - ------ + ...
'             2x3x4   4x5x6   6x7x8   8x9x10
i = pi = 0
numerator = -4
while i<10000
  i = i + 2
  numerator = -numerator
  pi = pi + numerator / (i * (i+1) * (i+2))
wend
pi = pi + 3
print using "#.##########";pi

Salida

6.2831853072

Si no puede entender lo que está sucediendo, aquí hay algunos consejos:

En Chipmunk Basic, la variable pi está preajustada al valor de π cuando el programa comienza a ejecutarse.

y

En BASIC, el signo igual se usa tanto para asignar variables como para probar la igualdad. Entonces a = b = c se interpreta como a = (b == c) .

ossifrage aprensivo
fuente
Espera, no lo entiendo, ¿ ies igual false? ¿Y luego le agregas 2? ¿¿¿Y funciona???
No sé
2
@Dunno: Claro, el bucle comienza en el i == falsecual es similar a i == 0. El punto es que el valor inicial para el acumulador pino es 0 ...
Bergi
1
@ Bergi, sí, simplemente no puedo entender el hecho de que false + 2 == 2: D
No sé
@Dunno Escritura dinámica, etc. También tiene el mismo comportamiento aparente en C, que carece de un booltipo, y utiliza un valor 0distinto de cero para representar falsey de forma trueselectiva. No es que sea elegante, pero bueno, así es como funciona.
Suzanne Dupéron
15

C - La longitud de la mitad de un círculo unitario

Una forma de calcular π es simplemente para medir la distancia que el punto (1, 0)se desplaza cuando se gira alrededor del origen a (-1, 0)ya que será la mitad de la circunferencia de un círculo de la unidad (que es ).

ingrese la descripción de la imagen aquí

Sin embargo, no hay sin(x)o cos(x)es necesario ya que esto se puede hacer mediante la intensificación de todo el camino alrededor del origen y la adición de la distancia al punto viaja para cada paso . Cuanto menor sea el tamaño de cada paso, más precisa será π .

Nota: Los pasos finalizarán cuando y esté por debajo de cero (que es justo cuando pasa (-1, 0)).

#include <stdio.h>                          // for printf
#define length(y, x) ((x * x) + (y * y))
int main()
{
    double x, y;
    double pi, tau, step;
    // start at (2, 0) which actually calculates tau
    x  = 2;
    y  = 0;
    // the step needs to be very low for high accuracy
    step = 0.00000001;  
    tau = 0;
    while (y >= 0)
    {   // the derivate of (x, y) is itself rotated 90 degrees
        double dx = -y;
        double dy = x;

        tau += length(dx, dy) * step; // add the distance for each step to tau
        // add the distance to the point (make a tiny rotation)
        x += dx * step;
        y += dy * step;
    }
    pi = tau / 2;   // divide tau with 2 to get pi

    /* ignore this line *\                      pi *= 2;    /* secret multiply ^-^ */

    // print the value of pi
    printf("Value of pi is %f", pi); getchar(); 
    return 0;
}

Da el siguiente resultado:

Value of pi is 6.283185
Thism2
fuente
3
Parece legítimo ... Definitivamente.
bjb568
1
A tu lengthmacro le falta un sqrt. ¿Eso es lo que se pretende? xy ytambién se intercambian entre la definición y la llamada (sin efecto)
Ben Voigt
@BenVoigt Shhh! No estropees el truco, pero sí. sqrtse omitió accidentalmente para que el valor de pi se imprimiera como 6,28 ... ¡También +1 por notar xy ylo que no hice!
Thism2
1
oh, ahora veo que no trazas un círculo unitario, sino uno con radio 2. Sí, eso funciona muy bien.
Ben Voigt
77
Debo confesar que antes de entender cómo funciona perdí un par de minutos al no haciendo caso omiso de esa línea ...
loreb
10

do

(Esto terminó siendo más largo de lo previsto, pero lo publicaré de todos modos ...)

En el siglo XVII, Wallis publicó una serie infinita para Pi:

ingrese la descripción de la imagen aquí

(Consulte Nuevos productos Infinitos de tipo Wallis y catalán para π, e y √ (2 + √2) para obtener más información)

Ahora, para calcular Pi, primero debemos multiplicar por dos para factorizar el denominador:

ingrese la descripción de la imagen aquí

Mi solución luego calcula las series infinitas para Pi / 2 y dos y luego multiplica los dos valores juntos. Tenga en cuenta que los productos infinitos son increíblemente lentos para converger al calcular los valores finales.

salida:

pi: 6.283182
#include "stdio.h"
#include "stdint.h"

#define ITERATIONS 10000000
#define one 1

#define IEEE_MANTISSA_MASK 0xFFFFFFFFFFFFFULL

#define IEEE_EXPONENT_POSITION 52
#define IEEE_EXPONENT_BIAS 1023

// want to get an exact as possible result, so convert
// to integers and do custom 64-bit multiplication.
double multiply(double aa, double bb)
{
    // the input values will be between 1.0 and 2.0
    // so drop these to less than 1.0 so as not to deal 
    // with the double exponents.
    aa /= 2;
    bb /= 2;

    // extract fractional part of double, ignoring exponent and sign
    uint64_t a = *(uint64_t*)&aa & IEEE_MANTISSA_MASK;
    uint64_t b = *(uint64_t*)&bb & IEEE_MANTISSA_MASK;

    uint64_t result = 0x0ULL;

    // multiplying two 64-bit numbers is a little tricky, this is done in two parts,
    // taking the upper 32 bits of each number and multiplying them, then
    // then doing the same for the lower 32 bits.
    uint64_t a_lsb = (a & 0xFFFFFFFFUL);
    uint64_t b_lsb = (b & 0xFFFFFFFFUL);

    uint64_t a_msb = ((a >> 32) & 0xFFFFFFFFUL);
    uint64_t b_msb = ((b >> 32) & 0xFFFFFFFFUL);

    uint64_t lsb_result = 0;
    uint64_t msb_result = 0;

    // very helpful link explaining how to multiply two integers
    // http://stackoverflow.com/questions/4456442/interview-multiplication-of-2-integers-using-bitwise-operators
    while(b_lsb != 0)
    {
        if (b_lsb & 01)
        {
            lsb_result = lsb_result + a_lsb;
        }
        a_lsb <<= 1;
        b_lsb >>= 1;
    }
    while(b_msb != 0)
    {
        if (b_msb & 01)
        {
            msb_result = msb_result + a_msb;
        }
        a_msb <<= 1;
        b_msb >>= 1;
    }

    // find the bit position of the most significant bit in the higher 32-bit product (msb_answer)
    uint64_t x2 = msb_result;
    int bit_pos = 0;
    while (x2 >>= 1)
    {
        bit_pos++;
    }

    // stuff bits from the upper 32-bit product into the result, starting at bit 51 (MSB of mantissa)
    int result_position = IEEE_EXPONENT_POSITION - 1;
    for(;result_position > 0 && bit_pos > 0; result_position--, bit_pos--)
    {
        result |= ((msb_result >> bit_pos) & 0x01) << result_position;
    }

    // find the bit position of the most significant bit in the lower 32-bit product (lsb_answer)
    x2 = lsb_result;
    bit_pos = 0;
    while (x2 >>= 1)
    {
        bit_pos++;
    }

    // stuff bits from the lowre 32-bit product into the result, starting at whatever position
    // left off at from above.
    for(;result_position > 0 && bit_pos > 0; result_position--, bit_pos--)
    {
        result |= ((lsb_result >> bit_pos) & 0x01) << result_position;
    }

    // create hex representation of the answer
    uint64_t r = (uint64_t)(/* exponent */ (uint64_t)IEEE_EXPONENT_BIAS << IEEE_EXPONENT_POSITION) |
            (uint64_t)( /* fraction */ (uint64_t)result & IEEE_MANTISSA_MASK);

    // stuff hex into double
    double d = *(double*)&r;

    // since the two input values were divided by two,
    // need to multiply by four to fix the result.
    d *= 4;

   return d;
}

int main()
{
    double pi_over_two = one;
    double two = one;

    double num = one + one;
    double dem = one;

    int i=0;

    i=ITERATIONS;
    while(i--)
    {
        // pi = 2 2 4 4 6 6 8 8 ...
        // 2    1 3 3 5 5 7 7 9
        pi_over_two *= num / dem;

        dem += one + one;

        pi_over_two *= num / dem;

        num += one + one;
    }

    num = one + one;
    dem = one;

    i=ITERATIONS;
    while(i--)
    {
        // 2 = 2 4 4 6   10 12 12 14
        //     1 3 5 7    9 11 13 15
        two *= num / dem;

        dem += one + one;
        num += one + one;

        two *= num / dem;

        dem += one + one;

        two *= num / dem;

        dem += one + one;
        num += one + one;

        two *= num / dem;

        dem += one + one;
        num += one + one + one + one;
    }

    printf("pi: %f\n", multiply(pi_over_two, two));

    return 0;
}

El exponente en la doble conversión en realidad no puede ser ignorado. Si ese es el único cambio (deja la división entre 2, la multiplicación por 4, la multiplicación entera) todo sorprendentemente funciona.


fuente
8

Java - Serie Nilakantha

La serie Nilakantha se da como:

pi = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) ...

Entonces, para cada término, el denominador se construye multiplicando enteros consecutivos, con el comienzo aumentando en 2 cada término. Observe que suma / resta términos alternos.

public class NilakanthaPi {
    public static void main(String[] args) {
        double pi = 0;
        // five hundred terms
        for(int t=1;t<500;t++){
            // each i is 2*term
            int i=t*2;
            double part = 4.0 / ((i*i*t)+(3*i*t)+(2*t));
            // flip sign for alternating terms
            if(t%2==0)
                pi -= part;
            else
                pi += part;
            // add 3 for first term
            if(t<=2)
                pi += 3;
        }
        System.out.println(pi);
    }
}

Después de quinientos términos, obtenemos una estimación razonable de pi:

6.283185311179568
Geobits
fuente
4

C ++: Madhava de Sangamagrama

Esta serie infinita ahora se conoce como Madhava-Leibniz :

Serie

Comience con la raíz cuadrada de 48 y multiplíquela por el resultado de la suma de (-3) -k / (2k + 1). Muy sencillo y sencillo de implementar:

long double findPi(int iterations)
{
    long double value = 0.0;

    for (int i = 0; i < iterations; i++) {
        value += powl(-3.0, -i) / (2 * i + 1);
    }

    return sqrtl(48.0) * value;
}

int main(int argc, char* argv[])
{
    std::cout << "my pi: " << std::setprecision(16) << findPi(1000) << std::endl;

    return 0;
}

Salida:

my pi: 6.283185307179588
Bruno Ferreira
fuente
3

Python: una alternativa a la serie Nilakantha

Esta es otra serie infinita para calcular pi que es bastante fácil de entender.

ingrese la descripción de la imagen aquí

Para esta fórmula, toma 6 y comienza a alternar entre sumar y restar fracciones con numeradores de 2 y denominadores que son el producto de dos enteros consecutivos y su suma. Cada fracción posterior comienza a aumentar su conjunto de enteros en 1. Realice esto incluso unas pocas veces y los resultados se acercarán bastante a pi.

pi = 6
sign = 1
for t in range(1,500):
i = t+1
   part = 2.0 / (i*t*(i+t))
   pi = pi + sign * part
   sign = - sign # flip sign for alternating terms  
print(pi)

lo que da 6.283185.

Thomas Oliveira
fuente
-1
#include "Math.h"
#include <iostream>
int main(){
    std::cout<<PI;
    return 0;
}

Math.h:

#include <Math.h>
#undef PI
#define PI 6.28

Salida: 6.28

#include "Math.h" no es lo mismo que #include, pero con solo mirar el archivo principal, casi nadie pensaría en verificarlo. Obvio, quizás, pero un problema similar apareció en un proyecto en el que estaba trabajando y no se detectó durante mucho tiempo.

Lucas
fuente
Una solución inteligente, no obstante.
BobTheAwesome