2015-11-11 4 views
0

Я написал несколько программ, чтобы найти pi, этот самый продвинутый. Я использовал формулу Мачина, pi/4 = 4(arc-tan(1/5)) - (arc-tan(1/239)).поиск pi - использование формулы Мачина. Различные итерации дают тот же результат

Проблема в том, что, несмотря на то, что у меня много итераций, я получаю тот же результат, и я не могу понять, почему.

#include "stdafx.h" 
#include <iostream> 
#include <iomanip> 
#include <math.h> 
using namespace std; 

double arctan_series(int x, double y) // x is the # of iterations while y  is the number 
{ 
    double pi = y; 
    double temp_Pi; 
    for (int i = 1, j = 3; i < x; i++, j += 2) 
    { 
     temp_Pi = pow(y, j)/j; //the actual value of the iteration 
     if (i % 2 != 0)  // for every odd iteration that subtracts 
     { 
      pi -= temp_Pi; 
     } 
     else // for every even iteration that adds 
     { 
      pi += temp_Pi; 
     } 
    } 
    pi = pi * 4; 
    return pi; 
} 

double calculations(int x) // x is the # of iterations 
{ 
    double value_1, value_2, answer; 
    value_1 = arctan_series(x, 0.2); 
    value_2 = arctan_series(x, 1.0/239.0); 
    answer = (4 * value_1) - (value_2); 
    return answer; 
} 

int main() 
{ 
    double pi; 
    int iteration_num; 
    cout << "Enter the number of iterations: "; 
    cin >> iteration_num; 
    pi = calculations(iteration_num); 
    cout << "Pi has the value of: " << setprecision(100) << fixed << pi  << endl; 
    return 0; 

} 
+0

Добро пожаловать в Переполнение стека! Похоже, вам, возможно, потребуется научиться использовать отладчик для выполнения вашего кода. С хорошим отладчиком вы можете выполнить свою программу по очереди и посмотреть, где она отклоняется от ожидаемого. Это важный инструмент, если вы собираетесь заниматься программированием. Дальнейшее чтение: ** [Как отлаживать небольшие программы] (http://ericlippert.com/2014/03/05/how-to-debug-small-programs/) ** – NathanOliver

ответ

0

Я не смог воспроизвести вашу проблему, но вот немного очищенный код с несколькими идиомами C++ 11 и лучшими именами переменных.

#include <iostream> 
#include <iomanip> 
#include <math.h> 

using namespace std; 

// double arctan_series(int x, double y) // x is the # of iterations while y  is the number 
// then why not name the parameters accoringly? In math we usually use x for the parameter. 
// prefer C++11 and the auto notation wherever possible 
auto arctan_series(int iterations, double x) -> double 
{ 
    // note, that we don't need any temporaries here. 

    // note, that this loop will never run, when iterations = 1 
    // is that really what was intended? 
    for (int i = 1, j = 3; i < iterations; i++, j += 2) 
    { 
     // declare variables as late as possible and always initialize them 
     auto t = pow(x, j)/j; 
     // in such simple cases I prefer ?: over if-else. Your milage may vary 
     x += (i % 2 != 0) ? -t : t; 
    } 
    return x * 4; 
} 

// double calculations(int x) // x is the # of iterations 
// then why not name the parameter accordingly 
// BTW rename the function to what it is supposed to do 
auto approximate_pi(int iterations) -> double 
{ 
    // we don't need all of these temporaries. Just write one expression. 
    return 4 * arctan_series(iterations, 0.2) - arctan_series(iterations, 1.0/239.0); 
} 

auto main(int, char**) -> int 
{ 
    cout << "Enter the number of iterations: "; 
    // in C++ you should declare variables as late as possible 
    // and always initialize them. 
    int iteration_num = 0; 
    cin >> iteration_num; 

    cout << "Pi has the value of: " 
     << setprecision(100) << fixed 
     << approximate_pi(iteration_num) << endl; 
    return 0; 
} 

При удалении мои пояснительные комментарии, вы увидите, что полученный код намного более кратким, легче читать, и, следовательно, проще в обслуживании.

Я попытался немного:

Enter the number of iterations: 3 
Pi has the value of: 3.1416210293250346197169164952356368303298950195312500000000000000000000000000000000000000000000000000 

Enter the number of iterations: 2 
Pi has the value of: 3.1405970293260603298790556436870247125625610351562500000000000000000000000000000000000000000000000000 

Enter the number of iterations: 7 
Pi has the value of: 3.1415926536235549981768144789384678006172180175781250000000000000000000000000000000000000000000000000 

Enter the number of iterations: 42 
Pi has the value of: 3.1415926535897940041763831686694175004959106445312500000000000000000000000000000000000000000000000000 

Как вы видите, я, очевидно, получить разные результаты для различных чисел итераций.

0

Этот метод сходится очень быстро. Вы получите больше точности, если сначала начнете с наименьших чисел. Так как 5^23> 2^53 (число бит в мантиссе двойника), вероятно, максимальное число итераций равно 12 (13 не будет иметь никакого значения). Вы получите больше точности, начиная с меньших чисел. Измененные строки имеют комментарии:

double arctan_series(int x, double y) 
{ 
    double pi = y; 
    double temp_Pi; 
    for (int i = 1, j = x*2-1; i < x; i++, j -= 2) // changed this line 
    { 
     temp_Pi = pow(y, j)/j; 
     if ((j & 2) != 0) // changed this line 
     { 
      pi -= temp_Pi; 
     } 
     else 
     { 
      pi += temp_Pi; 
     } 
    } 
    pi = pi * 4; 
    return pi; 
} 

Для двойников, нет никакого смысла в установлении точности> 18.

Если вы хотите альтернативную формулу, которая принимает большее количество итераций сходится, использование пи/4 = дуговом tan (1/2) + arc-tan (1/3), что займет около 24 итераций.

+0

извините, что делает и делает? Я знаю только & &. И это означает, что я не могу получить больше десятичных значений независимо от того, сколько итераций? –

+0

@IllorenzoAn - & is [побитовое и] (http://en.wikipedia.org/wiki/Bitwise_operation#AND). С 64-битным удвоением, 12 итераций с вашей формулой - это все, что вы можете получить. Вам нужно будет использовать некоторый тип расширенной математики (массивы), чтобы получить больше цифр. – rcgldr

+0

Хорошо, что имеет смысл. Есть ли отдельные библиотеки, которые я могу использовать? Или я должен использовать массивы? –

0

Это другой способ, если некоторые из вас заинтересованы. Цикл вычисляет интеграл функции: sqrt (1-x)

Что представляет собой полукруг радиуса 1. Затем умножим на две области. Наконец, мы получили поверхность круга, которая является PI.

#include <iomanip> 
#include <cmath> 

#define f(x) sqrt(1-pow(x,2)) 

double integral(int a, int b, int p) 
{ 
    double d=pow(10, -p), s=0; 
    for (double x=a ; x+d<=b ; x+=d) 
    { 
     s+=f(x)+f(x+d); 
    } 
    s*=d/2.0; 
    return s; 
} 

int main() 
{ 
    cout << "PI=" << setprecision (9) << 2.0*integral(-1,1,6) << endl; 
}