Как рассчитать PI в C #? - PullRequest
       261

Как рассчитать PI в C #?

27 голосов
/ 02 сентября 2008

Как я могу рассчитать значение PI, используя C #?

Я думал, что это будет через рекурсивную функцию, и если да, то как бы это выглядело, и есть ли математические уравнения, подтверждающие это?

Я не слишком беспокоюсь о производительности, в основном о том, как это делать с точки зрения обучения.

Ответы [ 21 ]

42 голосов
/ 02 сентября 2008

Если вы хотите рекурсию:

PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))

Это станет после некоторого переписывания:

PI = 2 * F(1);

с F (i):

double F (int i) {
    return 1 + i / (2.0 * i + 1) * F(i + 1);
}

Исаак Ньютон (возможно, вы слышали о нем раньше;)) придумал этот трюк. Обратите внимание, что я пропустил конечное условие, чтобы было проще. В реальной жизни вам это нужно.

23 голосов
/ 02 сентября 2008

Как насчет использования:

double pi = Math.PI;

Если вам нужна более высокая точность, вам необходимо использовать алгоритмическую систему и тип десятичного числа.

7 голосов
/ 26 ноября 2010

Если вы внимательно посмотрите на это действительно хорошее руководство:

Шаблоны для параллельного программирования: понимание и применение параллельных шаблонов в .NET Framework 4

Вы найдете на этой странице симпатичную реализацию (с небольшими изменениями с моей стороны):

static decimal ParallelPartitionerPi(int steps)
{
    decimal sum = 0.0;
    decimal step = 1.0 / (decimal)steps;
    object obj = new object();

    Parallel.ForEach(
        Partitioner.Create(0, steps),
        () => 0.0,
        (range, state, partial) =>
        {
            for (int i = range.Item1; i < range.Item2; i++)
            {
                decimal x = (i - 0.5) * step;
                partial += 4.0 / (1.0 + x * x);
            }

            return partial;
        },
        partial => { lock (obj) sum += partial; });

    return step * sum;
}
6 голосов
/ 03 сентября 2008

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

atan (1) == PI / 4, поэтому старый каштан, когда надежная функция арктангенса подарок 4 * атан (1).

Очень симпатичная оценка с фиксированным соотношением, которая делает старый Western 22/7 похожим на грязь 355/113, что хорошо с точностью до нескольких десятичных знаков (по крайней мере, три или четыре, я думаю). В некоторых случаях это даже достаточно для целочисленной арифметики: умножьте на 355, затем разделите на 113.

355/113 также легко зафиксировать в памяти (для некоторых людей в любом случае): сосчитайте одну, одну, три, три, пять, пять и помните, что вы называете цифры в знаменателе и числителе (если вы забыли какой триплет идет сверху, мысль микросекунды, как правило, исправит его).

Обратите внимание, что 22/7 дает вам: 3.14285714, что неверно в тысячных долях.

355/113 дает вам 3.14159292, что не так до десятимиллионных.

Точность. в /usr/include/math.h на моем ящике M_PI имеет значение # define'd как: +3,14159265358979323846 что, вероятно, хорошо, насколько это возможно.

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

355/113 - старая китайская оценка, и я полагаю, что она предшествует 22/7 по многим годам. Этому меня научил профессор физики, когда я был студентом.

4 голосов
/ 02 сентября 2008

Хороший обзор различных алгоритмов:

Я не уверен в сложности, заявленной для алгоритма Гаусса-Лежандра-Саламина в первой ссылке (я бы сказал, O (N log ^ 2 (N) log (log (N)))).

Я призываю вас попробовать, хотя конвергенция действительно быстрая.

Кроме того, я не совсем уверен, почему пытаюсь преобразовать довольно простой процедурный алгоритм в рекурсивный?

Обратите внимание, что если вы заинтересованы в производительности, то работа с ограниченной точностью (как правило, требующая 'double', 'float', ... output) на самом деле не имеет смысла, как очевидный ответ в таком случае просто жестко закодировать значение.

3 голосов
/ 02 сентября 2008

Вот статья о расчете PI в C #:

http://www.boyet.com/Articles/PiCalculator.html

2 голосов
/ 03 сентября 2008

Что такое ПИ? Окружность круга, деленная на его диаметр.

В компьютерной графике вы можете построить / нарисовать окружность с центром в точке 0,0 от начальной точки x, y, следующую точку x ', y' можно найти по простой формуле: x '= x + y / h: y' = y - x '/ h

h обычно является степенью 2, так что деление может быть легко выполнено с помощью сдвига (или вычитания из показателя степени в два раза). h также хочет быть радиусом r вашего круга. Легкой начальной точкой будет x = r, y = 0, а затем посчитать c количество шагов до x <= 0, чтобы построить четверть круга. PI 4 * C / R или PI 4 * C / H </p>

Рекурсия на любую большую глубину, как правило, нецелесообразна для коммерческой программы, но хвостовая рекурсия позволяет рекурсивно выражать алгоритм при его реализации в виде цикла. Иногда рекурсивные алгоритмы поиска могут быть реализованы с использованием очереди, а не стека процесса, при поиске необходимо вернуться из тупика и выбрать другой путь - эти точки возврата могут быть помещены в очередь, а несколько процессов могут снять их с очереди и попробовать другие пути.

1 голос
/ 02 сентября 2008

Вот хороший подход (из основная запись в Википедии на пи ); он сходится гораздо быстрее, чем простая формула, рассмотренная выше, и вполне поддается рекурсивному решению, если вы намерены использовать рекурсию как учебное упражнение. (Предполагая, что вы прошли обучение, я не даю никакого реального кода.)

Основная формула такая же, как и выше, но этот подход усредняет частичные суммы для ускорения сходимости.

Определите двухпараметрическую функцию pie (h, w), такую ​​что:

pie(0,1) = 4/1
pie(0,2) = 4/1 - 4/3
pie(0,3) = 4/1 - 4/3 + 4/5
pie(0,4) = 4/1 - 4/3 + 4/5 - 4/7
... and so on

Таким образом, ваша первая возможность исследовать рекурсию - это кодирование этого «горизонтального» вычисления при увеличении параметра «ширина» (для «высоты», равной нулю).

Затем добавьте второе измерение с этой формулой:

pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2

который используется, конечно, только для значений h больше нуля.

Приятной особенностью этого алгоритма является то, что вы можете легко смоделировать его с помощью электронной таблицы для проверки кода при изучении результатов, полученных с помощью постепенно увеличивающихся параметров. К тому времени, когда вы вычисляете pie (10,10), у вас будет приблизительное значение для pi, которое достаточно для большинства инженерных целей.

1 голос
/ 02 сентября 2008

Рассчитать так:

x = 1 - 1/3 + 1/5 - 1/7 + 1/9  (... etc as far as possible.)
PI = x * 4

У тебя есть Пи !!!

Это самый простой из известных мне методов.

Значение PI медленно сходится к фактическому значению Pi (3.141592165 ......). Если вы повторяете больше раз, тем лучше.

1 голос
/ 03 сентября 2014
using System;

namespace Strings
{
    class Program
    {
        static void Main(string[] args)
        {

/*          decimal pie = 1; 
            decimal e = -1;
*/
            var stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start(); //added this nice stopwatch start routine 

  //leibniz formula in C# - code written completely by Todd Mandell 2014
/*
            for (decimal f = (e += 2); f < 1000001; f++)
            {
                 e += 2;
                 pie -= 1 / e;
                 e += 2;
                 pie += 1 / e;
                 Console.WriteLine(pie * 4);
            }

                 decimal finalDisplayString = (pie * 4);
                 Console.WriteLine("pie = {0}", finalDisplayString);
                 Console.WriteLine("Accuracy resulting from approximately {0} steps", e/4); 
*/

// Nilakantha formula - code written completely by Todd Mandell 2014
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - (4/(12*13*14) etc

            decimal pie = 0;
            decimal a = 2;
            decimal b = 3;
            decimal c = 4;
            decimal e = 1;

            for (decimal f = (e += 1); f < 100000; f++) 
            // Increase f where "f < 100000" to increase number of steps
            {

                pie += 4 / (a * b * c);

                a += 2;
                b += 2;
                c += 2;

                pie -= 4 / (a * b * c);

                a += 2;
                b += 2;
                c += 2;

                e += 1;
            }

            decimal finalDisplayString = (pie + 3);
            Console.WriteLine("pie = {0}", finalDisplayString);
            Console.WriteLine("Accuracy resulting from {0} steps", e); 

            stopwatch.Stop();
            TimeSpan ts = stopwatch.Elapsed;
            Console.WriteLine("Calc Time {0}", ts); 

            Console.ReadLine();

         }
     }
 }
...