Вопрос

Как я могу вычислить значение PI с помощью C #?

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

double pi = Math.PI;

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

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

Шаблоны для параллельного программирования: понимание и применение параллельных шаблонов в .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;
}

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

atan(1) == PI / 4, таким образом, старый каштан, когда присутствует надежная функция касательной к дуге , равен 4 * atan(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.Этому научил меня профессор физики, когда я был старшекурсником.

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

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

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

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

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

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

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

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

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

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

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

Рассчитайте так:

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

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

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

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

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

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

Определите двухпараметрическую функцию 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

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

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

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

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

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

Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
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();

         }
     }
 }
    public static string PiNumberFinder(int digitNumber)
    {
        string piNumber = "3,";
        int dividedBy = 11080585;
        int divisor = 78256779;
        int result;

        for (int i = 0; i < digitNumber; i++)
        {
            if (dividedBy < divisor)
                dividedBy *= 10;

            result = dividedBy / divisor;

            string resultString = result.ToString();
            piNumber += resultString;

            dividedBy = dividedBy - divisor * result;
        }

        return piNumber;
    }

В любом производственном сценарии я заставляю вас искать значение с желаемым количеством десятичных знаков и сохранять его как «const» там, где ваши классы могут получить его.

(если вы не пишете научное программное обеспечение для Pi) ...

Относительно...

...как это сделать с точки зрения обучения?

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

В любом случае, я думаю, что написание собственного Pi - решаемая проблема.Дмитрий уже показал константу 'Math.PI'.Решите другую проблему в том же пространстве!Используйте общие ньютоновские аппроксимации или что-нибудь более изящное.

@ Томас Каммейер:

Обратите внимание, что Atan (1.0) довольно часто жестко запрограммирован, поэтому 4 * Atan (1.0) на самом деле не является «алгоритмом», если вы вызываете библиотечную функцию Atan (довольно многие из уже предложенных действительно приступают к замене Atan ( x) по серии (или бесконечному произведению) для него, затем оценивая его при x = 1.

Кроме того, очень мало случаев, когда вам понадобится пи с большей точностью, чем несколько десятков битов (это может быть легко закодировано!). Я работал над приложениями в математике, где, чтобы вычислить некоторые (довольно сложные) математические объекты (которые были полиномиальными с целыми коэффициентами), мне пришлось выполнять арифметику с действительными и комплексными числами (включая вычисление числа Пи) с точностью до несколько миллионов бит ... но это не очень часто "в реальной жизни":)

Вы можете посмотреть следующий пример код .

Мне нравится этот документ , в котором объясняется, как рассчитывать & # 960; основанный на разложении в ряд Тейлора для Арктангента.

Статья начинается с простого предположения, что

  

Atan (1) = & # 960; / 4 радиана

Атан (х) может быть итеративно оценен с помощью ряда Тейлора

  

atan (x) = x - x ^ 3/3 + x ^ 5/5 - x ^ 7/7 + x ^ 9/9 ...

В статье указывается, почему это не особенно эффективно, и продолжается внесение ряда логических улучшений в технику. Они также предоставляют пример программы, которая вычисляет & # 960; до нескольких тысяч цифр, с исходным кодом, включая математические процедуры бесконечной точности.

Следующая ссылка показывает, как вычислить константу pi на основе ее определения как интеграла, который может быть записан как предел суммирования, это очень интересно: https://sites.google.com/site/rcorcs/posts/calculationthepiconstant Файл & Quot; Pi как целое & Quot; объясняет этот метод, используемый в этом посте.

Во-первых, обратите внимание, что C # может использовать поле Math.PI .NET Framework:

https: // msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx

Приятной особенностью здесь является то, что это двойная точность с полной точностью, которую вы можете использовать или сравнить с вычисленными результатами. Вкладки по этому URL имеют аналогичные константы для C ++, F # и Visual Basic.

Чтобы рассчитать больше мест, вы можете написать свой собственный код с расширенной точностью. Тот, который быстро кодировать и достаточно быстро и легко программировать:

Pi = 4 * [4 * арктан (1/5) - арктан (1/239)]

Эта формула и многие другие, включая те, которые сходятся с удивительно высокой скоростью, например, 50 цифр в семестре, в Wolfram:

Формулы Вольфрама Пи

Число ПИ (π) может быть рассчитан с помощью бесконечный ряд.Вот два примера:

Серия Грегори-Лейбница:

π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...

Метод C # :

public static decimal GregoryLeibnizGetPI(int n)
{
    decimal sum = 0;
    decimal temp = 0;
    for (int i = 0; i < n; i++)
    {
        temp = 4m / (1 + 2 * i);
        sum += i % 2 == 0 ? temp : -temp;
    }
    return sum;
}

Серия Нилаканта:

π = 3 + 4 / (2x3x4) - 4 / (4x5x6) + 4 / (6x7x8) - 4 / (8x9x10) + ...

Метод C #:

public static decimal NilakanthaGetPI(int n)
{
    decimal sum = 0;
    decimal temp = 0;
    decimal a = 2, b = 3, c = 4;
    for (int i = 0; i < n; i++)
    {
        temp = 4 / (a * b * c);
        sum += i % 2 == 0 ? temp : -temp;
        a += 2; b += 2; c += 2;
    }
    return 3 + sum;
}

Входной параметр n для обеих функций представляет собой количество итераций.

Ряд Нилаканты по сравнению с рядом Грегори-Лейбница сходится быстрее.Эти методы можно протестировать с помощью следующего кода:

static void Main(string[] args)
{
    const decimal pi = 3.1415926535897932384626433832m;
    Console.WriteLine($"PI = {pi}");

    //Nilakantha Series
    int iterationsN = 100;
    decimal nilakanthaPI = NilakanthaGetPI(iterationsN);
    decimal CalcErrorNilakantha = pi - nilakanthaPI;
    Console.WriteLine($"\nNilakantha Series -> PI = {nilakanthaPI}");
    Console.WriteLine($"Calculation error = {CalcErrorNilakantha}");
    int numDecNilakantha = pi.ToString().Zip(nilakanthaPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
    Console.WriteLine($"Number of correct decimals = {numDecNilakantha}");
    Console.WriteLine($"Number of iterations = {iterationsN}");

    //Gregory-Leibniz Series
    int iterationsGL = 1000000;
    decimal GregoryLeibnizPI = GregoryLeibnizGetPI(iterationsGL);
    decimal CalcErrorGregoryLeibniz = pi - GregoryLeibnizPI;
    Console.WriteLine($"\nGregory-Leibniz Series -> PI = {GregoryLeibnizPI}");
    Console.WriteLine($"Calculation error = {CalcErrorGregoryLeibniz}");
    int numDecGregoryLeibniz = pi.ToString().Zip(GregoryLeibnizPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
    Console.WriteLine($"Number of correct decimals = {numDecGregoryLeibniz}");
    Console.WriteLine($"Number of iterations = {iterationsGL}");

    Console.ReadKey();
}

Следующий результат показывает, что ряд Нилаканты возвращает шесть правильных десятичных чисел числа PI за сто итераций, тогда как ряд Грегори-Лейбница возвращает пять правильных десятичных чисел числа PI за миллион итераций:

enter image description here

Мой код можно протестировать >> здесь

Вот хороший способ: Рассчитайте ряд 1 / x ^ 2 для x от 1 до того, что вы хотите - чем больше число, тем лучше результат. Умножьте результат на 6 и до sqrt (). Вот код на C # (только основной):

static void Main(string[] args)
    {
        double counter = 0;
        for (double i = 1; i < 1000000; i++)
        {

            counter = counter + (1 / (Math.Pow(i, 2)));

        }
        counter = counter * 6;
        counter = Math.Sqrt(counter);
        Console.WriteLine(counter);
    }
public double PI = 22.0 / 7.0;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top