Pi hala yanlıştır [kapalı]


27

Pi Yanlış

Pi hesaplamanın yaygın bir yöntemi, 1x1 kutuya "dart" atmak ve birim çemberdeki toprağı atılan toplam ile karşılaştırmaktır:

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

Pi'yi doğru hesaplaması gerektiği gibi görünen bir program yazın (bu ya da diğer ortak hesaplama yöntemlerini kullanarak) ancak tau değerini hesaplayın (tau = 2 * pi = 6.283185307179586 ...). Kodunuz en az ilk 6 ondalık basamağı oluşturmalıdır: 6.283185

Kazanan 6 Haziran'da taçlandı (bugünden bir hafta sonra).


43
Neden kazanan 28 Haziran'da taçlandırılmadı?
corsiKa

9
Bir kazananın neden popülerlik yarışmasında taçlandırılması gerektiğinden emin değilim.
Tim S.

1
Anlamadım. Bu, geri dönüş gibi görünen 1fakat geri dönen bir fonksiyon istemek gibi 2. Burada kimi kandırıyoruz?
ja72

3
@ ja72 Kodun okuyucusu :)
14:14

8
Herkes pau'nun doğru olduğunu biliyor . : P
Justin Krejcha

Yanıtlar:


57

JavaScript

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

Yardım et, bir evren fabrikasında mahsur kaldım ve ne yaptığımdan emin değilim. Math.atan2pi'yi iyi değerlerle döndürmek gerekiyor, değil mi? Math.atan2(0, -0)pi'yi döndürür, eğer çıkarırsam ve eklersem yine de pi olmalıyım.


14
Sanırım gidip uzanıp ağlayacağım. Allah kahretsin, JavaScript.
Jack M

3
açıklama lütfen :)
Jaa-c

2
X ekseni ile nokta (Y, X) arasındaki radyan olarak saatin tersi yönde açı Y noktasının işareti, bunun pozitif mi yoksa negatif bir açı mı olduğunu belirler ve bu olurπ - (-π)

8
0_o >>> 0 === -0 ;true ;>>> Math.atan2(0, 0) ;0 ;>>> Math.atan2(0, -0) ;3.141592653589793
Izkata

5
@JackM, bu ifadeyi söylemek her zaman uygun olur :) Bu durumda, IEEE standardına bağlı olmasına rağmen ve birçok dilde (sadece JS için değil) sıfır ile negatif sıfır arasında sorun var.
Paul Draper

40

TEMEL

(Daha spesifik olarak, Chipmunk Basic )

Bu , 15. yüzyılda Nilakantha Somayaji tarafından keşfedilen sonsuz bir seri kullanıyor :

' 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

Çıktı

6.2831853072

Neler olduğunu çözemezseniz, işte birkaç ipucu:

Chipmunk Basic'te, program çalışmaya başladığında pi değişkeni π değerine önceden ayarlanmıştır.

ve

BASIC'te, eşittir işareti hem değişkenleri atamak hem de eşitliği test etmek için kullanılır. Yani a = b = c , a = (b == c) olarak yorumlanır .


Bekle alamadım, ieşit falsemi? Ve sonra eklediniz 2mi? Ve çalışıyor???
Dunno

2
@Dunno: Tabii ki, hangi döngüler i == falsebenzer olduğu başlar i == 0. Mesele şu ki, akümülatör için başlangıç ​​değeri pi0…
Bergi

1
@Bergi evet, kafamı şu gerçeğin etrafına saramıyorum false + 2 == 2: D
Dunno

@Dunno Dinamik yazarak etc .: false, aritmetik işlem yaparken 0'a dönüştürülür. Ayrıca, C'de bir booltürden yoksun görünen aynı davranışı görürsünüz ve kullanıp 0sıfırdan farklı şekilde temsil eder falseve temsil eder true. Zarif değil, ama hey, işte böyle çalışıyor.
Suzanne Dupéron

15

C - Yarım birim dairenin uzunluğu

Hesaplamak için bir yol tt noktası mesafeyi ölçmek için basitçe (1, 0)etrafında döndürürken hareket kökeni için (-1, 0)bir yarı çevresi olacaktır çünkü birim çember (ki ).

görüntü tanımını buraya girin

Ancak, hiçbir sin(x)ya cos(x)bu yana gereklidir yapılabilir adım etrafında tüm yol kökeni ve nokta her adım için seyahat mesafe ekleyerek . Her adım için daha küçük boyut daha doğru π alırsınız.

Not: Adımlama, y ​​sıfırın altına düştüğünde sona erecektir (bu tam olarak geçtiği gibi (-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;
}

Aşağıdaki çıktıyı verir:

Value of pi is 6.283185

3
Yasal görünüyor ... Kesinlikle.
bjb568

1
Kişisel lengthMakro bir sqrt eksik. Bu amaçlandı mı? xve yaynı zamanda tanım ve çağrı arasında da değişmektedir (etkisiz)
Ben Voigt

@BenVoigt Shhh! Numarayı bozma ama evet. sqrtedildi yanlışlıkla pi değerinin Farkettiğin için de +1 ... 6,28 olarak çıktı ki ihmal xve yhangi ı değil mi!
Bum2

1
oh, şimdi görüyorum ki bir birim daire değil, yarıçap 2 ile bir tane izliyorsunuz.
Ben Voigt

7
Nasıl çalıştığını anlamadan önce birkaç dakika harcadığımı itiraf etmeliyim ki ...
loreb

10

C

(Bu amaçlanandan daha uzun sürdü, ama yine de göndereceğim ...)

17. yüzyılda Wallis, Pi için sonsuz bir dizi yayınladı:

görüntü tanımını buraya girin

(Daha fazla bilgi için , bkz. Π, e ve for için Yeni Wallis ve Katalan Tipi Sonsuz Ürünler (2 + √2) )

Şimdi, Pi'yi hesaplamak için, önce paydayı hesaba katmak için iki ile çarpmalıyız:

görüntü tanımını buraya girin

Benim çözümüm daha sonra Pi / 2 ve iki için sonsuz serileri hesaplar ve sonra iki değeri birlikte çoğaltır. Sonsuz ürünlerin nihai değerleri hesaplarken bir araya gelmesi inanılmaz derecede yavaş olduğuna dikkat edin.

çıktı:

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;
}

İkili dönüşümdeki üs gerçekten göz ardı edilemez. Tek değişiklik buysa (bölmeyi 2 saniye, 4 ile çarp, tam sayı çarpma) her şey şaşırtıcı şekilde çalışır.


8

Java - Nilakantha Serisi

Nilakantha Serisi aşağıdaki gibidir:

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

Böylece, her bir terim için, payda ardışık tamsayıların çarpılmasıyla oluşturulur, başlangıçta her terim 2 artar. Alternatif terimler eklediğiniz / çıkardığınıza dikkat edin.

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);
    }
}

Beş yüz terimden sonra, pi'nin makul bir tahminini alıyoruz:

6.283185311179568

4

C ++: Sangamagrama Medresesi

Bu sonsuz seri şimdi Madhava-Leibniz olarak bilinir :

Dizi

48 karekökü ile başlayın ve (-3) -k / (2k + 1) toplamı ile çarpın . Uygulaması çok basit ve basittir:

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;
}

Çıktı:

my pi: 6.283185307179588

3

Python - Nilakantha serisine bir alternatif

Pi'yi hesaplamak için anlaşılması oldukça kolay olan bir başka sonsuz seri.

görüntü tanımını buraya girin

Bu formül için, 6'yı alın ve iki ardışık tamsayının ürünü olan paydalar ve bunların toplamları ile paydaları 2 sayılarıyla toplama ve çıkarma arasında değişmeye başlayın. Sonraki her bir fraksiyon, 1 ile yükselen tam sayı kümesini başlatır. Bunu birkaç defa bile yapın ve sonuçlar pi'ye oldukça yaklaşır.

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)

6.283185'i verir.


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

math.h:

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

Çıktı: 6.28

#include "Math.h" #include ile aynı değildir, fakat sadece ana dosyaya bakarak neredeyse hiç kimse kontrol etmeyi düşünmez. Açıkçası, ancak üzerinde çalıştığım bir projede benzer bir konu ortaya çıktı ve uzun süredir tespit edilemedi.


Yine de akıllıca bir çözüm.
BobTheAwesome
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.