Глава 6. Вычисление числа π
Одиннадцать первых цифр числа π = 3,1415926535… легко запомнить с помощью такой мнемоники:
«Кто и шутя и скоро пожелаетъ пи узнать число, ужъ знаетъ».
Её придумали до реформы русской орфографии 1918 года, поэтому и буквы «ѥръ» в конце слов после согласных.
Для приближённого вычисления числа π применяются разные методы.
Один из способов (на практике не очень удобный) связан с вычислением бесконечной суммы (ряда) Лейбница: 1 − 1 3 + 1 5 − 1 7 + … = ∑ i = 0 ∞ − 1 i 2 i + 1 = π 4 .
Можно получить π из суммы другого ряда — ряда Эйлера: 1 + 1 2 2 + 1 3 2 + … = ∑ i = 1 ∞ 1 i 2 = π 2 6 .
Естественно, на компьютере невозможно осуществить вычисление бесконечной суммы. Однако в математическом анализе доказывается, что оба ряда сходятся. Это значит, что последовательности частных сумм стремятся к некоторым числам (в наших примерах к π 4 и π 2 6 ), то есть сумма достаточно большого количества слагаемых ряда даст хорошее приближение для суммы. Задавшись требуемой точностью, можно даже указать необходимые количества слагаемых, чтобы обеспечить вычисление с этой точностью (конечно, без учёта ошибок округления при выполнении арифметических действий — такие ошибки очень трудно контролировать).
Рассмотрим геометрическую прогрессию со знаменателем − 1 : 1 − 1 + 1 − 1 + … Найдём её сумму S : S = 1 − 1 + 1 − 1 + … = 1 − 1 − 1 + 1 − … . Заметим, что выражение в скобках ничем не отличается от выражения для S : S = 1 − S . Отсюда находим, что S = 1 2 .
Всё это очень странно…
Сходится не всякий ряд. Единственный ряд, изучаемый в школе — геометрическая прогрессия: 1 + q + q 2 + q 3 + q 4 + … = ∑ i = 0 ∞ q i . Его сходимость зависит от q : ряд сходится лишь при q < 1 . В этом случае сумма, как известно, равна 1 1 − q .
Для сходимости необходимо, чтобы последовательность слагаемых стремилась к нулю. Но это условие не является достаточным.
Наряду с бесконечными суммами (рядами) рассматривают также бесконечные произведения и другие бесконечные выражения.
Число пи на клавиатуре и в Word
Существует несколько способов ввода числа Пи, как с клавиатуры компьютера, так и с помощью простого копирования. Опишем, как проще всего написать число Пи.
Способ — 1.
Вот символ числа Пи — π . Просто скопируйте его и вставьте в свой документ.
Способ — 2, для PC.
Нажмите клавишу Alt и не отпуская ее введите код символа числа π — «960» или «227«, отпустите «Alt«. Клавиша Alt находится в нижней части, как правило, слева и справа от клавиши «Пробел«. Цифровой код нужно вводить с помощью цифровой клавиатуры находящейся спава.
Способ — 3, для MAC
Нажмите клавишу «Option» и не отпуская клавишу «P«, появится символ числа Пи.
Способ — 4, получение числа Пи в Ворде или в другом текстовом редакторе
В Word-е, в окне выбора шрифта, выберите шрифт Symbol и нажмите букву «P«.
Способ — 5, таблица символов.
В операционной системе Windows необходимо открыть программу «Таблица символов«. Для этого воспользуйтесь меню «Пуск» — «Все программы» — «Служебные«. В таблице символов выбираем нужный нам шрифт и ищем символ числа Pi в огромном многообразии различных символов.
Кстати, не со всеми шрифтами символ числа Пи будет корректно отображаться. Лучше всего для этого подходит шрифт «Times New Roman«.
Как вычислить число пи на компьютере
Самый простой и легкий в реализации метод.
Рассмотрим произвольный квадрат с центром в начале координат и вписанный в него круг. Будем рассматривать только первую координатную четверть. В ней будет находиться четверть круга и четверть квадрата. Обозначим радиус круга r, тогда четверть квадрата тоже будет квадратом(очевидно) со стороной r.
Будем случайным образом выбирать точки в этом квадрате и считать количество точек, попавших в четверть круга. Благодаря теории вероятности мы знаем, что отношение попаданий в четверть круга к попаданиям ‘в молоко’ равно отношению площадей — пи/4. Вот, собственно, и весь алгоритм. Чем больше взятых наугад точек мы проверим, тем точнее будет отношение площадей.
Вот простенькая программа на Паскале, считающая пи этим способом. Четыре первых знака требуют на моем PentiumII-300 около 5 минут.
uses Crt; const n=10000000; r=46340; r2=46340*46340; var i,pass : LongInt; x,y : real; begin WriteLn('Поехали!'); Randomize; pass:=0; for i:=1 to n do begin x:=Random(r+1); y:=Random(r+1); if ( x*x+y*y < r2 ) then INC(pass); end; TextColor(GREEN); WriteLn('Число ПИ получилось равным: ',(pass/i*4):0:5); ReadLn; end.
Однако, как говорил Козьма Прутков, 'нельзя объять необъятное', что, в применении к данному случаю, можно перефразировать так: нельзя просуммировать бесконечное число слагаемых за конечное время, каким бы быстрым компьютером мы не располагали.
Слава Богу, этого и не требуется. Поскольку мы хотим найти не точное значение PI, а лишь его приближение с пятью верными десятичными знаками, нам достаточно просуммировать такое количество первых членов ряда, чтобы сумма всех оставшихся членов не превышала 10 -5 .
Остался, правда, открытым вопрос о том, сколько же все-таки членов ряда нужно просуммировать, чтобы получить результат с требуемой точностью?
Ответ на этот вопрос в 'общем виде' выходит далеко за рамки настоящего обсуждения. Это отдельная тема в курсах математического анализа и численных методов.
К счастью, данный конкретный ряд позволяет найти очень простое правило, позволяющее определить момент, когда следует прекратить суммирование. Дело в том, что ряд Грегори является знакопеременным и сходится равномерно (хотя и медленнее, чем хотелось бы). Это означает, что для любого нечетного n , сумма первых n членов ряда всегда дает верхнюю оценку для PI, а сумма n +1 первых членов ряда - нижнюю.
Значит, как только разница между верхней и нижней оценками окажется меньше, чем требуемая точность, можно смело прекращать вычисления и быть уверенным, что как та, так и другая оценки отличаются от истинного значения PI не более, чем на 10 -5 . В качестве окончательного результата разумно взять среднее значение между полученными верхней и нижней оценками. Таким образом, можно предложить алгоритм, приведенный ниже.
Положить n=0, S1 = 0 и S2 = 0; ( начальные установки ) Увеличить n на 1; ( n становится нечетным ) Вычислить S1 = S2 + 4/(2n-1); (S1 - есть верхняя оценка ) Увеличить n на 1; ( n становится четным ) Вычислить S2 = S1 - 4/(2n-1); (S2 - есть нижняя оценка) Если S1 - S2 >= 10^(-5) перейти к шагу 2; ( нужная точность еще не достигнута ) Напечатать результат (S1 + S2) / 2
При реализации этого алгоритма на машине следует помнить, что ряд Грегори сходится достаточно медленно, и поэтому n может принимать довольно большие значения.
Для вычисления сколько-нибудь большого количества знаков пи предыдущий способ уже не годится. Но существует большое количество последовательностей, сходящихся к Пи гораздо быстрее. Воспользуемся, например, формулой Гаусса:
| p | = 12arctan | 1 | + 8arctan | 1 | - 5arctan | 1 |
| 4 | 18 | 57 | 239 |
Доказательство этой формулы несложное, поэтому мы его опустим.
Исходник программы, включающий в себя 'длинную арифметику'
Программа вычисляет NbDigits первых цифр числа Пи. Функция вычисления arctan названа arccot, так как arctan(1/p) = arccot(p), но расчет происходит по формуле Тейлора именно для арктангенса, а именно arctan(x) = x - x 3 /3 + x 5 /5 - . x=1/p, значит arccot(x) = 1/p - 1 / p 3 / 3 + . Вычисления происходят рекурсивно: предыдущий элемент суммы делится и дает следующий.
/* ** Pascal Sebah : September 1999 ** ** Subject: ** ** A very easy program to compute Pi with many digits. ** No optimisations, no tricks, just a basic program to learn how ** to compute in multiprecision. ** ** Formulae: ** ** Pi/4 = arctan(1/2)+arctan(1/3) (Hutton 1) ** Pi/4 = 2*arctan(1/3)+arctan(1/7) (Hutton 2) ** Pi/4 = 4*arctan(1/5)-arctan(1/239) (Machin) ** Pi/4 = 12*arctan(1/18)+8*arctan(1/57)-5*arctan(1/239) (Gauss) ** ** with arctan(x) = x - x^3/3 + x^5/5 - . ** ** The Lehmer's measure is the sum of the inverse of the decimal ** logarithm of the pk in the arctan(1/pk). The more the measure ** is small, the more the formula is efficient. ** For example, with Machin's formula: ** ** E = 1/log10(5)+1/log10(239) = 1.852 ** ** Data: ** ** A big real (or multiprecision real) is defined in base B as: ** X = x(0) + x(1)/B^1 + . + x(n-1)/B^(n-1) ** where 0 Work with double instead of long and the base B can ** be choosen as 10^8 ** => During the iterations the numbers you add are smaller ** and smaller, take this in account in the +, *, / ** => In the division of y=x/d, you may precompute 1/d and ** avoid multiplications in the loop (only with doubles) ** => MaxDiv may be increased to more than 3000 with doubles ** => . */ #include #include #include #include long B=10000; /* Working base */ long LB=4; /* Log10(base) */ long MaxDiv=450; /* about sqrt(2^31/B) */ /* ** Set the big real x to the small integer Integer */ void SetToInteger (long n, long *x, long Integer) < long i; for (i=1; i/* ** Is the big real x equal to zero ? */ long IsZero (long n, long *x) < long i; for (i=0; i/* ** Addition of big reals : x += y ** Like school addition with carry management */ void Add (long n, long *x, long *y) < long carry=0, i; for (i=n-1; i>=0; i--) < x[i] += y[i]+carry; if (x[i]> > /* ** Substraction of big reals : x -= y ** Like school substraction with carry management ** x must be greater than y */ void Sub (long n, long *x, long *y) < long i; for (i=n-1; i>=0; i--) < x[i] -= y[i]; if (x[i]<0) < if (i) < x[i] += B; x[i-1]--; >> > > /* ** Multiplication of the big real x by the integer q ** x = x*q. ** Like school multiplication with carry management */ void Mul (long n, long *x, long q) < long carry=0, xi, i; for (i=n-1; i>=0; i--) < xi = x[i]*q; xi += carry; if (xi>=B) < carry = xi/B; xi -= (carry*B); >else carry = 0; x[i] = xi; > > /* ** Division of the big real x by the integer d ** The result is y=x/d. ** Like school division with carry management ** d is limited to MaxDiv*MaxDiv. */ void Div (long n, long *x, long d, long *y) < long carry=0, xi, q, i; for (i=0; i> /* ** Find the arc cotangent of the integer p (that is arctan (1/p)) ** Result in the big real x (size n) ** buf1 and buf2 are two buffers of size n */ void arccot (long p, long n, long *x, long *buf1, long *buf2) < long p2=p*p, k=3, sign=0; long *uk=buf1, *vk=buf2; SetToInteger (n, x, 0); SetToInteger (n, uk, 1); /* uk = 1/p */ Div (n, uk, p, uk); Add (n, x, uk); /* x = uk */ while (!IsZero(n, uk)) < if (p/* One step for small p */ else < Div (n, uk, p, uk); /* Two steps for large p (see division) */ Div (n, uk, p, uk); > /* uk = u(k-1)/(p^2) */ Div (n, uk, k, vk); /* vk = uk/k */ if (sign) Add (n, x, vk); /* x = x+vk */ else Sub (n, x, vk); /* x = x-vk */ k+=2; sign = 1-sign; > > /* ** Print the big real x */ void Print (long n, long *x) < long i; printf ("%d.", x[0]); for (i=1; iprintf ("\n"); > /* ** Computation of the constant Pi with arctan relations */ void main () < clock_t endclock, startclock; long NbDigits=10000, NbArctan; long p[10], m[10]; long size=1+NbDigits/LB, i; long *Pi = (long *)malloc(size*sizeof(long)); long *arctan = (long *)malloc(size*sizeof(long)); long *buffer1 = (long *)malloc(size*sizeof(long)); long *buffer2 = (long *)malloc(size*sizeof(long)); startclock = clock(); /* ** Formula used: ** ** Pi/4 = 12*arctan(1/18)+8*arctan(1/57)-5*arctan(1/239) (Gauss) */ NbArctan = 3; m[0] = 12; m[1] = 8; m[2] = -5; p[0] = 18; p[1] = 57; p[2] = 239; SetToInteger (size, Pi, 0); /* ** Computation of Pi/4 = Sum(i) [m[i]*arctan(1/p[i])] */ for (i=0; i0) Add (size, Pi, arctan); else Sub (size, Pi, arctan); > Mul (size, Pi, 4); endclock = clock (); Print (size, Pi); /* Print out of Pi */ printf ("Computation time is : %9.2f seconds\n", (float)(endclock-startclock)/(float)CLOCKS_PER_SEC ); free (Pi); free (arctan); free (buffer1); free (buffer2); >
Конечно, это не самые эффективные способы вычисления числа пи. Существует еще громадное количество формул. Например, формула Чудновского (Chudnovsky), разновидности которой используются в Maple. Однако в обычной практике программирования формулы Гаусса вполне хватает, поэтому эти методы не будут описываться в статье. Вряд ли кто-то хочет вычислять миллиарды знаков пи, для которых сложная формула дает большое увеличение скорости.
Как заставить ПК вычислить число пи максимально точно?
Привет ЛОР. Как вычислить точное число Пи? Зачем? Да интересно стало сколько его будет вычислять мой ПК (cpu точнее, расчеты на gpu не берем). В идеале хотелось бы задать много-много знаков, ну хотя бы 20к знаков числа Пи как вычислить? В программировании я ноль.
Линукс тут при том, что вычисления будут вестись в нем, ведь всем известно, что все супер-пупер компьютеры работают на Линуксе.

karton1 ★★★★★
27.01.18 19:00:09 MSK
← 1 2 →

Его нельзя вычислить максимально точно, оно иррациональное.
hateyoufeel ★★★★★
( 27.01.18 19:05:53 MSK )

greenman ★★★★★
( 27.01.18 19:07:27 MSK )
Ответ на: комментарий от hateyoufeel 27.01.18 19:05:53 MSK
Можно, если работать с системой счисления с подходящим основанием - например, с пи-ической.
Begemoth ★★★★★
( 27.01.18 19:07:54 MSK )
Ответ на: комментарий от Begemoth 27.01.18 19:07:54 MSK

hateyoufeel ★★★★★
( 27.01.18 19:10:08 MSK )
Выбирай свой любимый язык программирования:
П.С. Гугл знает всё!
yvv ★★☆
( 27.01.18 19:12:39 MSK )

В идеале хотелось бы задать много-много знаков, ну хотя бы 20к знаков числа Пи как вычислить?
soomrack ★★★★
( 27.01.18 19:16:34 MSK )

redgremlin ★★★★★
( 27.01.18 19:18:54 MSK )
Прекрати прогуливать уроки. Твой учитель математики вам об этом рассказывал.
ты ноль не только в программировании.
Deleted
( 27.01.18 19:23:46 MSK )
Ответ на: комментарий от Deleted 27.01.18 19:23:46 MSK

Математику я прогуливал когда она была в школе, мне она не нравилась. А сейчас на заочке на вышмате упомянули про число Пи, вот я и задумался.
karton1 ★★★★★
( 27.01.18 19:24:39 MSK ) автор топика
Последнее исправление: karton1 27.01.18 19:25:02 MSK (всего исправлений: 2)
Ответ на: комментарий от karton1 27.01.18 19:24:39 MSK

вычисляй сразу pi^e
Avial ★★★★★
( 27.01.18 19:25:25 MSK )
Ответ на: комментарий от Avial 27.01.18 19:25:25 MSK

А чем это круче чем вычисление числа Пи? Я помню что это как то связано с Эйлером.
karton1 ★★★★★
( 27.01.18 19:30:20 MSK ) автор топика

Забавный факт. При попытке открыть в браузере файл с числом Пи вычисленным с точностью до миллиарда ПК завис. Файрфокс последний, cpu ryzen 1500x. Пишу с xiaomi.
karton1 ★★★★★
( 27.01.18 19:31:32 MSK ) автор топика
Ответ на: комментарий от karton1 27.01.18 19:30:20 MSK

одно трансцендентное иррациональное число в степени другого иррационального трансцендентного числа - это разве не весело?
Avial ★★★★★
( 27.01.18 19:32:02 MSK )
Ответ на: комментарий от Avial 27.01.18 19:32:02 MSK

Мда, выглядит мощно.
karton1 ★★★★★
( 27.01.18 19:33:35 MSK ) автор топика
Ответ на: комментарий от karton1 27.01.18 19:24:39 MSK

Так ты мазохист?
fornlr ★★★★★
( 27.01.18 19:36:06 MSK )
Ответ на: комментарий от fornlr 27.01.18 19:36:06 MSK

Почему ты так решил?
karton1 ★★★★★
( 27.01.18 19:36:54 MSK ) автор топика
Ответ на: комментарий от karton1 27.01.18 19:36:54 MSK

Математику я прогуливал когда она была в школе, мне она не нравилась. А сейчас на заочке на вышмате
Или я что не понял.
Я вот в школе терпеть не мог только одну вещь - русский язык и литературу. Как вспомню про сочинения, аж в дрожь с тошнотой бросает. Вот бы поступил на филологический 😀
fornlr ★★★★★
( 27.01.18 19:38:43 MSK )
Последнее исправление: fornlr 27.01.18 19:39:33 MSK (всего исправлений: 1)
Ответ на: комментарий от fornlr 27.01.18 19:38:43 MSK

Хах, у меня наоборот. Я был самый читающий в школе, меня даже награждали за это, книгу подарили из библиотеки, лол, поэтому русский язык и литература были вообще не проблемой, я их тупо знал, даже не учил. А вот математику я быстро освоить не могу как это требовали на уроке, а дома изучать скучно было, компа и интернета к тому же не было, я просто обкладывался книгами и читал. Фантастику всегда любил, научную, про космос там, будущее.