Какой самый быстрый способ получить значение & # 960 ;?
https://stackoverflow.com/questions/19
Вопрос
Я ищу самый быстрый способ получить значение π как личный вызов. Более конкретно, я использую способы, которые не включают использование констант #define
, таких как M_PI
, или жесткое кодирование числа в.
В приведенной ниже программе проверяются различные известные мне способы. Версия inline сборки, теоретически, является самым быстрым вариантом, хотя и явно не переносимым. Я включил его в качестве основы для сравнения с другими версиями. В моих тестах со встроенными версиями версия 4 * atan (1)
была самой быстрой в GCC 4.2, поскольку она автоматически складывает atan (1)
в константу , Если указан -fno-builtin
, версия atan2 (0, -1)
является самой быстрой.
Вот основная программа тестирования ( pitimes.c
):
#include <math.h>
#include <stdio.h>
#include <time.h>
#define ITERS 10000000
#define TESTWITH(x) { \
diff = 0.0; \
time1 = clock(); \
for (i = 0; i < ITERS; ++i) \
diff += (x) - M_PI; \
time2 = clock(); \
printf("%s\t=> %e, time => %f\n", #x, diff, diffclock(time2, time1)); \
}
static inline double
diffclock(clock_t time1, clock_t time0)
{
return (double) (time1 - time0) / CLOCKS_PER_SEC;
}
int
main()
{
int i;
clock_t time1, time2;
double diff;
/* Warmup. The atan2 case catches GCC's atan folding (which would
* optimise the ``4 * atan(1) - M_PI'' to a no-op), if -fno-builtin
* is not used. */
TESTWITH(4 * atan(1))
TESTWITH(4 * atan2(1, 1))
#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
extern double fldpi();
TESTWITH(fldpi())
#endif
/* Actual tests start here. */
TESTWITH(atan2(0, -1))
TESTWITH(acos(-1))
TESTWITH(2 * asin(1))
TESTWITH(4 * atan2(1, 1))
TESTWITH(4 * atan(1))
return 0;
}
И встроенные компоненты сборки ( fldpi.c
), которые будут работать только для систем x86 и x64:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
И скрипт сборки, который собирает все конфигурации, которые я тестирую ( build.sh
):
#!/bin/sh
gcc -O3 -Wall -c -m32 -o fldpi-32.o fldpi.c
gcc -O3 -Wall -c -m64 -o fldpi-64.o fldpi.c
gcc -O3 -Wall -ffast-math -m32 -o pitimes1-32 pitimes.c fldpi-32.o
gcc -O3 -Wall -m32 -o pitimes2-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -fno-builtin -m32 -o pitimes3-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -ffast-math -m64 -o pitimes1-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall -m64 -o pitimes2-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall -fno-builtin -m64 -o pitimes3-64 pitimes.c fldpi-64.o -lm
Помимо тестирования между различными флагами компилятора (я также сравнил 32-битные с 64-битными, потому что оптимизации разные), я также попытался изменить порядок тестов. Но, тем не менее, версия atan2 (0, -1)
по-прежнему выходит на первое место каждый раз.
Решение
метод Монте-Карло , как уже упоминалось, применяет некоторые замечательные концепции, но, очевидно, не самый быстрый, ни в дальнем плане, ни в какой-либо разумной мере. Кроме того, все зависит от того, какую точность вы ищете. Самый быстрый π, который я знаю, это тот, у которого цифры жестко запрограммированы. Посмотрите на Pi и Pi [PDF] , есть много формул.
Вот метод, который быстро сходится - около 14 цифр за итерацию. PiFast , текущее самое быстрое приложение, использует эту формулу с БПФ. Я просто напишу формулу, так как код прост. Эта формула была почти найдена Рамануджаном и обнаружена Чудновским . Это на самом деле, как он вычислил несколько миллиардов цифр числа, так что это не метод игнорировать. Формула быстро переполнится, и, поскольку мы делим факториалы, было бы целесообразно отложить такие вычисления, чтобы удалить термины.
Ниже приведен алгоритм Брента – Саламина . В Википедии упоминается, что когда a и b "достаточно близки" тогда (a + b) ² / 4t будет приближением π. Я не уверен, что "достаточно близко" значит, но из моих тестов одна итерация получила 2 цифры, две - 7, а три - 15, конечно, это с двойными числами, поэтому может возникнуть ошибка на основе ее представления и вычисления true может быть более точным.
let pi_2 iters =
let rec loop_ a b t p i =
if i = 0 then a,b,t,p
else
let a_n = (a +. b) /. 2.0
and b_n = sqrt (a*.b)
and p_n = 2.0 *. p in
let t_n = t -. (p *. (a -. a_n) *. (a -. a_n)) in
loop_ a_n b_n t_n p_n (i - 1)
in
let a,b,t,p = loop_ (1.0) (1.0 /. (sqrt 2.0)) (1.0/.4.0) (1.0) iters in
(a +. b) *. (a +. b) /. (4.0 *. t)
Наконец, как насчет пи-гольфа (800 цифр)? 160 символов!
int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);}
Другие советы
Мне очень нравится эта программа, потому что она приблизительно равна & # 960; глядя на свою территорию.
IOCCC 1988: westley.c
#define _ -F<00||--F-OO--; int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ _-_-_-_ }
Вот общее описание методики расчета числа пи, которую я выучил в старшей школе.
Я делюсь этим только потому, что думаю, что это достаточно просто, чтобы каждый мог помнить об этом на неопределенный срок, плюс он учит вас понятию «Монте-Карло». методы, которые представляют собой статистические методы получения ответов, которые не сразу выводятся из случайных процессов.
Нарисуйте квадрат и нарисуйте квадрант (одну четверть полукруга) внутри этого квадрата (квадрант с радиусом, равным стороне квадрата, поэтому он заполняет как можно большую часть квадрата)
Теперь бросьте дротик в квадрат и запишите, где он находится, то есть выберите случайную точку в любом месте квадрата. Конечно, он приземлился внутри квадрата, но внутри полукруга? Запишите этот факт.
Повторите этот процесс много раз - и вы увидите, что есть соотношение количества точек внутри полукруга к общему количеству брошенных, назовите это соотношение x.
Поскольку площадь квадрата r раз r, вы можете сделать вывод, что площадь полукруга равна x раз r раз r (то есть x умножено на квадрат). Следовательно, х раз 4 даст вам пи. Р>
Это не быстрый метод для использования. Но это хороший пример метода Монте-Карло. И если вы оглянетесь вокруг, вы можете обнаружить, что с помощью этих методов можно решить многие проблемы, не относящиеся к вашим вычислительным навыкам.
В интересах полноты, версия шаблона C ++, которая для оптимизированной сборки будет вычислять приближение PI во время компиляции и будет встроена в одно значение.
#include <iostream>
template<int I>
struct sign
{
enum {value = (I % 2) == 0 ? 1 : -1};
};
template<int I, int J>
struct pi_calc
{
inline static double value ()
{
return (pi_calc<I-1, J>::value () + pi_calc<I-1, J+1>::value ()) / 2.0;
}
};
template<int J>
struct pi_calc<0, J>
{
inline static double value ()
{
return (sign<J>::value * 4.0) / (2.0 * J + 1.0) + pi_calc<0, J-1>::value ();
}
};
template<>
struct pi_calc<0, 0>
{
inline static double value ()
{
return 4.0;
}
};
template<int I>
struct pi
{
inline static double value ()
{
return pi_calc<I, I>::value ();
}
};
int main ()
{
std::cout.precision (12);
const double pi_value = pi<10>::value ();
std::cout << "pi ~ " << pi_value << std::endl;
return 0;
}
Примечание для I > 10, оптимизированные сборки могут быть медленными, также как и для неоптимизированных запусков. Я полагаю, что за 12 итераций существует около 80 тыс. Вызовов value () (при отсутствии запоминания).
На самом деле есть целая книга, посвященная (среди прочего) быстрым методам для вычисления \ pi: 'Pi и AGM' Джонатана и Питера Боровейна ( доступно на Amazon ).
Я немного изучил AGM и связанные с ним алгоритмы: это довольно интересно (хотя иногда нетривиально).
Обратите внимание, что для реализации большинства современных алгоритмов для вычисления \ pi вам потребуется многоточная арифметическая библиотека ( GMP достаточно хороший выбор, хотя я давно его использовал).
Сложность по времени лучших алгоритмов находится в O (M (n) log (n)), где M (n) - сложность по времени для умножения двух n-битных целых чисел (M (n) = O (n log (n) log (log (n))) с использованием алгоритмов на основе FFT, которые обычно необходимы при вычислении цифр \ pi, и такой алгоритм реализован в GMP).
Обратите внимание, что хотя математика, лежащая в основе алгоритмов, может и не быть тривиальной, сами алгоритмы обычно представляют собой несколько строк псевдокода, и их реализация обычно очень проста (если вы решили не писать свою собственную арифметику мультиточности: - )). Р>
Ниже приведен точный ответ , как это сделать максимально быстро - с наименьшими вычислительными затратами . Даже если вам не нравится ответ, вы должны признать, что это действительно самый быстрый способ получить значение PI.
БЫСТРЫЙ способ получить значение Pi:
1) выбрал свой любимый язык программирования 2) загрузить свою математическую библиотеку 3) и найдите, что Pi там уже определен - готов к использованию!
Если у вас нет математической библиотеки под рукой ..
Способ ВТОРОЙ БЫСТРЫЙ (более универсальное решение):
найдите Пи в Интернете, например, здесь:
http://www.eveandersson.com/pi/digits/1000000 (1 миллион цифр .. какова ваша точность с плавающей запятой?)
или здесь:
http://3.14159265358979323846264338327950288419716939934510.com / p
или здесь: http://en.wikipedia.org/wiki/Pi Очень быстро найти нужные цифры для любой точной арифметики, которую вы хотели бы использовать, и определив константу, вы можете быть уверены, что не тратите драгоценное процессорное время. Мало того, что это отчасти юмористический ответ, но на самом деле, если бы кто-нибудь пошел дальше и вычислил значение Pi в реальном приложении ... это было бы довольно большой тратой процессорного времени, не так ли? По крайней мере, я не вижу реального приложения для попытки пересчитать это. Уважаемый модератор: обратите внимание, что ОП спросил: " Самый быстрый способ получить значение PI "
формула BBP позволяет вычислять n-ю цифру - в базе 2 (или 16) - без необходимости сначала беспокоиться о предыдущих n-1 цифрах:)
Вместо того, чтобы определять pi как константу, я всегда использую acos (-1)
.
Только что наткнулся на этот, который должен быть здесь для полноты:
У него есть довольно приятное свойство: точность можно повысить, увеличив программу. Р>
Вот некоторые сведения о самом языке
Если эта статья верна, то алгоритм, который создал Беллард , может быть одним из самых быстрых из доступных. Он создал пи до 2,7 триллиона цифр с помощью настольного ПК!
... и он опубликовал свою работу здесь
Хорошая работа, Беллард, ты пионер!
Это "классика" метод, очень прост в реализации. Эта реализация в Python (не очень быстрый язык) делает это:
from math import pi
from time import time
precision = 10**6 # higher value -> higher precision
# lower value -> higher speed
t = time()
calc = 0
for k in xrange(0, precision):
calc += ((-1)**k) / (2*k+1.)
calc *= 4. # this is just a little optimization
t = time()-t
print "Calculated: %.40f" % calc
print "Costant pi: %.40f" % pi
print "Difference: %.40f" % abs(calc-pi)
print "Time elapsed: %s" % repr(t)
Вы можете найти дополнительную информацию здесь .
В любом случае, самый быстрый способ получить точное число пи в python, сколько вам нужно, это:
from gmpy import pi
print pi(3000) # the rule is the same as
# the precision on the previous code
вот фрагмент исходного кода для метода gmpy pi, я не думаю, что в этом случае код будет столь же полезен, как и комментарий:
static char doc_pi[]="\
pi(n): returns pi with n bits of precision in an mpf object\n\
";
/* This function was originally from netlib, package bmp, by
* Richard P. Brent. Paulo Cesar Pereira de Andrade converted
* it to C and used it in his LISP interpreter.
*
* Original comments:
*
* sets mp pi = 3.14159... to the available precision.
* uses the gauss-legendre algorithm.
* this method requires time o(ln(t)m(t)), so it is slower
* than mppi if m(t) = o(t**2), but would be faster for
* large t if a faster multiplication algorithm were used
* (see comments in mpmul).
* for a description of the method, see - multiple-precision
* zero-finding and the complexity of elementary function
* evaluation (by r. p. brent), in analytic computational
* complexity (edited by j. f. traub), academic press, 1976, 151-176.
* rounding options not implemented, no guard digits used.
*/
static PyObject *
Pygmpy_pi(PyObject *self, PyObject *args)
{
PympfObject *pi;
int precision;
mpf_t r_i2, r_i3, r_i4;
mpf_t ix;
ONE_ARG("pi", "i", &precision);
if(!(pi = Pympf_new(precision))) {
return NULL;
}
mpf_set_si(pi->f, 1);
mpf_init(ix);
mpf_set_ui(ix, 1);
mpf_init2(r_i2, precision);
mpf_init2(r_i3, precision);
mpf_set_d(r_i3, 0.25);
mpf_init2(r_i4, precision);
mpf_set_d(r_i4, 0.5);
mpf_sqrt(r_i4, r_i4);
for (;;) {
mpf_set(r_i2, pi->f);
mpf_add(pi->f, pi->f, r_i4);
mpf_div_ui(pi->f, pi->f, 2);
mpf_mul(r_i4, r_i2, r_i4);
mpf_sub(r_i2, pi->f, r_i2);
mpf_mul(r_i2, r_i2, r_i2);
mpf_mul(r_i2, r_i2, ix);
mpf_sub(r_i3, r_i3, r_i2);
mpf_sqrt(r_i4, r_i4);
mpf_mul_ui(ix, ix, 2);
/* Check for convergence */
if (!(mpf_cmp_si(r_i2, 0) &&
mpf_get_prec(r_i2) >= (unsigned)precision)) {
mpf_mul(pi->f, pi->f, r_i4);
mpf_div(pi->f, pi->f, r_i3);
break;
}
}
mpf_clear(ix);
mpf_clear(r_i2);
mpf_clear(r_i3);
mpf_clear(r_i4);
return (PyObject*)pi;
}
<Ч>
РЕДАКТИРОВАТЬ . У меня возникли проблемы с вырезкой, вставкой и идентификацией. В любом случае вы можете найти источник здесь .
Если под самым быстрым вы подразумеваете самый быстрый ввод кода, вот решение golfscript
;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
Используйте формулу, подобную машинной
176 * arctan (1/57) + 28 * arctan (1/239) - 48 * arctan (1/682) + 96 * arctan(1/12943)
[; \left( 176 \arctan \frac{1}{57} + 28 \arctan \frac{1}{239} - 48 \arctan \frac{1}{682} + 96 \arctan \frac{1}{12943}\right) ;], for you TeX the World people.
Реализовано в схеме, например:
(+ (- (+ (* 176 (атан (/ 1 57)))) (* 28 (атан (/ 1 239)))) (* 48 (атан (/ 1 682)))) (* 96 (атан (/ 1 12943))))
Если вы хотите использовать приближение, 355/113
подходит для 6 десятичных цифр и имеет дополнительное преимущество, заключающееся в возможности использования с целочисленными выражениями. Это не так важно в наши дни, как «математический сопроцессор с плавающей запятой» перестал иметь какое-либо значение, но это было довольно важно однажды.
С двойным числом:
4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))
Это будет с точностью до 14 знаков после запятой, что достаточно для заполнения двойного (неточность, вероятно, связана с тем, что остальные десятичные дроби в арктангенсах усекаются).
Также Сет, это 3,14159265358979323846 3 , а не 64.
Рассчитать PI во время компиляции с помощью D.
(Скопировано из DSource.org ) р>
/** Calculate pi at compile time
*
* Compile with dmd -c pi.d
*/
module calcpi;
import meta.math;
import meta.conv;
/** real evaluateSeries!(real x, real metafunction!(real y, int n) term)
*
* Evaluate a power series at compile time.
*
* Given a metafunction of the form
* real term!(real y, int n),
* which gives the nth term of a convergent series at the point y
* (where the first term is n==1), and a real number x,
* this metafunction calculates the infinite sum at the point x
* by adding terms until the sum doesn't change any more.
*/
template evaluateSeries(real x, alias term, int n=1, real sumsofar=0.0)
{
static if (n>1 && sumsofar == sumsofar + term!(x, n+1)) {
const real evaluateSeries = sumsofar;
} else {
const real evaluateSeries = evaluateSeries!(x, term, n+1, sumsofar + term!(x, n));
}
}
/*** Calculate atan(x) at compile time.
*
* Uses the Maclaurin formula
* atan(z) = z - z^3/3 + Z^5/5 - Z^7/7 + ...
*/
template atan(real z)
{
const real atan = evaluateSeries!(z, atanTerm);
}
template atanTerm(real x, int n)
{
const real atanTerm = (n & 1 ? 1 : -1) * pow!(x, 2*n-1)/(2*n-1);
}
/// Machin's formula for pi
/// pi/4 = 4 atan(1/5) - atan(1/239).
pragma(msg, "PI = " ~ fcvt!(4.0 * (4*atan!(1/5.0) - atan!(1/239.0))) );
Пи ровно 3! [Профессор Фринк (Симпсоны)]
Шутка, но вот один в C # (требуется .NET-Framework).
using System;
using System.Text;
class Program {
static void Main(string[] args) {
int Digits = 100;
BigNumber x = new BigNumber(Digits);
BigNumber y = new BigNumber(Digits);
x.ArcTan(16, 5);
y.ArcTan(4, 239);
x.Subtract(y);
string pi = x.ToString();
Console.WriteLine(pi);
}
}
public class BigNumber {
private UInt32[] number;
private int size;
private int maxDigits;
public BigNumber(int maxDigits) {
this.maxDigits = maxDigits;
this.size = (int)Math.Ceiling((float)maxDigits * 0.104) + 2;
number = new UInt32[size];
}
public BigNumber(int maxDigits, UInt32 intPart)
: this(maxDigits) {
number[0] = intPart;
for (int i = 1; i < size; i++) {
number[i] = 0;
}
}
private void VerifySameSize(BigNumber value) {
if (Object.ReferenceEquals(this, value))
throw new Exception("BigNumbers cannot operate on themselves");
if (value.size != this.size)
throw new Exception("BigNumbers must have the same size");
}
public void Add(BigNumber value) {
VerifySameSize(value);
int index = size - 1;
while (index >= 0 && value.number[index] == 0)
index--;
UInt32 carry = 0;
while (index >= 0) {
UInt64 result = (UInt64)number[index] +
value.number[index] + carry;
number[index] = (UInt32)result;
if (result >= 0x100000000U)
carry = 1;
else
carry = 0;
index--;
}
}
public void Subtract(BigNumber value) {
VerifySameSize(value);
int index = size - 1;
while (index >= 0 && value.number[index] == 0)
index--;
UInt32 borrow = 0;
while (index >= 0) {
UInt64 result = 0x100000000U + (UInt64)number[index] -
value.number[index] - borrow;
number[index] = (UInt32)result;
if (result >= 0x100000000U)
borrow = 0;
else
borrow = 1;
index--;
}
}
public void Multiply(UInt32 value) {
int index = size - 1;
while (index >= 0 && number[index] == 0)
index--;
UInt32 carry = 0;
while (index >= 0) {
UInt64 result = (UInt64)number[index] * value + carry;
number[index] = (UInt32)result;
carry = (UInt32)(result >> 32);
index--;
}
}
public void Divide(UInt32 value) {
int index = 0;
while (index < size && number[index] == 0)
index++;
UInt32 carry = 0;
while (index < size) {
UInt64 result = number[index] + ((UInt64)carry << 32);
number[index] = (UInt32)(result / (UInt64)value);
carry = (UInt32)(result % (UInt64)value);
index++;
}
}
public void Assign(BigNumber value) {
VerifySameSize(value);
for (int i = 0; i < size; i++) {
number[i] = value.number[i];
}
}
public override string ToString() {
BigNumber temp = new BigNumber(maxDigits);
temp.Assign(this);
StringBuilder sb = new StringBuilder();
sb.Append(temp.number[0]);
sb.Append(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);
int digitCount = 0;
while (digitCount < maxDigits) {
temp.number[0] = 0;
temp.Multiply(100000);
sb.AppendFormat("{0:D5}", temp.number[0]);
digitCount += 5;
}
return sb.ToString();
}
public bool IsZero() {
foreach (UInt32 item in number) {
if (item != 0)
return false;
}
return true;
}
public void ArcTan(UInt32 multiplicand, UInt32 reciprocal) {
BigNumber X = new BigNumber(maxDigits, multiplicand);
X.Divide(reciprocal);
reciprocal *= reciprocal;
this.Assign(X);
BigNumber term = new BigNumber(maxDigits);
UInt32 divisor = 1;
bool subtractTerm = true;
while (true) {
X.Divide(reciprocal);
term.Assign(X);
divisor += 2;
term.Divide(divisor);
if (term.IsZero())
break;
if (subtractTerm)
this.Subtract(term);
else
this.Add(term);
subtractTerm = !subtractTerm;
}
}
}
В этой версии (на Delphi) нет ничего особенного, но она, по крайней мере, быстрее, чем версия Ника Ходжа, размещенная в его блоге :). На моем компьютере для выполнения миллиарда итераций требуется около 16 секунд, что дает значение 3.14159265 25879 (точная часть выделена жирным шрифтом).
program calcpi;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
start, finish: TDateTime;
function CalculatePi(iterations: integer): double;
var
numerator, denominator, i: integer;
sum: double;
begin
{
PI may be approximated with this formula:
4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 .......)
//}
numerator := 1;
denominator := 1;
sum := 0;
for i := 1 to iterations do begin
sum := sum + (numerator/denominator);
denominator := denominator + 2;
numerator := -numerator;
end;
Result := 4 * sum;
end;
begin
try
start := Now;
WriteLn(FloatToStr(CalculatePi(StrToInt(ParamStr(1)))));
finish := Now;
WriteLn('Seconds:' + FormatDateTime('hh:mm:ss.zz',finish-start));
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
В прежние времена, с маленькими размерами слов и медленными или несуществующими операциями с плавающей запятой, мы привыкли делать что-то вроде этого:
/* Return approximation of n * PI; n is integer */
#define pi_times(n) (((n) * 22) / 7)
Для приложений, которые не требуют высокой точности (например, для видеоигр), это очень быстро и достаточно точно.
Если вы хотите вычислить аппроксимацию значения π (по некоторым причинам), вам следует попробовать алгоритм двоичного извлечения. улучшение Белларда в BBP дает значение PI в O (N ^ 2). Р> <Ч>
Если вы хотите получить приближение значения π для выполнения вычислений, тогда:
PI = 3.141592654
Конечно, это только приблизительное значение, и не совсем точное. Это немного больше, чем 0,00000000004102. (четыре десять триллионных, около 4 / 10 000 000 000 ).
<Ч>Если вы хотите сделать математику с π, то возьмите себе карандаш и бумагу или пакет компьютерной алгебры и используйте точное значение π, π. Р>
Если вам действительно нужна формула, она будет забавной:
π = - i ln (-1)
Метод Брента, опубликованный Крисом выше, очень хорош; Брент, как правило, гигант в области арифметики произвольной точности.
Если вам нужна только цифра N, формула BBP полезно в шестнадцатеричном виде
Вычисление π из площади круга: -)
<input id="range" type="range" min="10" max="960" value="10" step="50" oninput="calcPi()">
<br>
<div id="cont"></div>
<script>
function generateCircle(width) {
var c = width/2;
var delta = 1.0;
var str = "";
var xCount = 0;
for (var x=0; x <= width; x++) {
for (var y = 0; y <= width; y++) {
var d = Math.sqrt((x-c)*(x-c) + (y-c)*(y-c));
if (d > (width-1)/2) {
str += '.';
}
else {
xCount++;
str += 'o';
}
str += " "
}
str += "\n";
}
var pi = (xCount * 4) / (width * width);
return [str, pi];
}
function calcPi() {
var e = document.getElementById("cont");
var width = document.getElementById("range").value;
e.innerHTML = "<h4>Generating circle...</h4>";
setTimeout(function() {
var circ = generateCircle(width);
e.innerHTML = "<pre>" + "π = " + circ[1].toFixed(2) + "\n" + circ[0] +"</pre>";
}, 200);
}
calcPi();
</script>
Лучший подход
Чтобы получить выходные данные стандартных констант, таких как pi или стандартных концепций, мы должны сначала использовать встроенные методы, доступные на языке, который вы используете. Он вернет значение самым быстрым и лучшим способом. Я использую python, чтобы получить самый быстрый способ получить значение pi
- переменная pi математической библиотеки . В библиотеке Math переменная pi хранится как константа.
import math
print math.pi
Запустите скрипт с утилитой времени из linux / usr / bin / time -v python math_pi.py
Command being timed: "python math_pi.py"
User time (seconds): 0.01
System time (seconds): 0.01
Percent of CPU this job got: 91%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
- Используйте метод математики arc cos
import math
print math.acos(-1)
Запустите скрипт с утилитой времени из linux / usr / bin / time -v python acos_pi.py
Command being timed: "python acos_pi.py"
User time (seconds): 0.02
System time (seconds): 0.01
Percent of CPU this job got: 94%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
- используйте формулу BBP
from decimal import Decimal, getcontext
getcontext().prec=100
print sum(1/Decimal(16)**k *
(Decimal(4)/(8*k+1) -
Decimal(2)/(8*k+4) -
Decimal(1)/(8*k+5) -
Decimal(1)/(8*k+6)) for k in range(100))
Запустите скрипт с утилитой времени из linux / usr / bin / time -v python bbp_pi.py
Command being timed: "python c.py"
User time (seconds): 0.05
System time (seconds): 0.01
Percent of CPU this job got: 98%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.06
Так что лучше всего использовать встроенный метод, предоставляемый языком, потому что он самый быстрый и лучший для получения результата. В Python используйте math.pi