Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 获取π;值的最快方法是什么;?_Performance_Algorithm_Language Agnostic_Unix_Pi - Fatal编程技术网

Performance 获取π;值的最快方法是什么;?

Performance 获取π;值的最快方法是什么;?,performance,algorithm,language-agnostic,unix,pi,Performance,Algorithm,Language Agnostic,Unix,Pi,作为个人挑战,我正在寻找获得π值的最快方法。更具体地说,我使用的方法不涉及使用#定义常量,如m_PI,或硬编码中的数字 下面的程序测试了我所知道的各种方法。从理论上讲,内联汇编版本是最快的选择,但显然不可移植。我把它作为一个基线,与其他版本进行比较。在我的测试中,内置的4*atan(1)版本在GCC4.2上速度最快,因为它自动将atan(1)折叠成一个常量。如果指定了-fno内置,则atan2(0,-1)版本最快 这是主要的测试程序(pitimes.c): #包括 #包括 #包括 #定义ITER

作为个人挑战,我正在寻找获得π值的最快方法。更具体地说,我使用的方法不涉及使用
#定义
常量,如
m_PI
,或硬编码中的数字

下面的程序测试了我所知道的各种方法。从理论上讲,内联汇编版本是最快的选择,但显然不可移植。我把它作为一个基线,与其他版本进行比较。在我的测试中,内置的
4*atan(1)
版本在GCC4.2上速度最快,因为它自动将
atan(1)
折叠成一个常量。如果指定了
-fno内置
,则
atan2(0,-1)
版本最快

这是主要的测试程序(
pitimes.c
):

#包括
#包括
#包括
#定义ITER10000000
#定义TESTWITH(x){\
差异=0.0\
time1=时钟()\
对于(i=0;i%e,time=>%f\n”,#x,diff,diffclock(time2,time1))\
}
静态内联双精度
diffclock(时钟时间1,时钟时间0)
{
返回(双倍)(时间1-时间0)/时钟每秒;
}
int
main()
{
int i;
时钟时间1,时间2;
双差;
/*预热。atan2案例捕捉到GCC的atan折叠(这将
*将“4*atan(1)-M_PI”优化为无操作,如果-fno内置
*没有使用*/
测试(4*atan(1))
测试(4*atan2(1,1))
#如果已定义(uuu GNUC_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
外部双fldpi();
TESTWITH(fldpi())
#恩迪夫
/*实际测试从这里开始*/
TESTWITH(atan2(0,-1))
测试(acos(-1))
测试(2*asin(1))
测试(4*atan2(1,1))
测试(4*atan(1))
返回0;
}
以及仅适用于x86和x64系统的内联汇编材料(
fldpi.c
):

double
民阵()
{
双pi;
asm(“fldpi”:“=t”(pi));
返回pi;
}
以及一个构建脚本,用于构建我正在测试的所有配置(
build.sh
):


除了在各种编译器标志之间进行测试(我也比较了32位和64位,因为优化是不同的),我还尝试了切换测试顺序。但是,atan2(0,-1)
版本仍然每次都是最受欢迎的。

以下是我在高中时学习的一种计算圆周率的技术的概述

我之所以这么说,是因为我认为它足够简单,任何人都可以无限期地记住它,而且它还教会了你“蒙特卡罗”方法的概念——这是一种统计方法,用来得出答案,而不是通过随机过程立即推断出来

画一个正方形,在正方形内刻一个象限(四分之一个半圆)(一个半径等于正方形侧面的象限,因此它尽可能填满正方形)

现在向正方形投掷一个飞镖,并记录它落在哪里——也就是说,在正方形内的任意位置选择一个随机点。当然,它降落在广场内,但它在半圆内吗?记录下这个事实

重复这个过程很多次,你会发现半圆内的点数与抛出的总数的比率,称之为x

因为正方形的面积是r乘以r,所以可以推断出半圆的面积是x乘以r乘以r(即x乘以r的平方)。因此x乘以4将得到π

这不是一个快速使用的方法。但这是蒙特卡罗方法的一个很好的例子。如果你环顾四周,你可能会发现许多超出你计算能力的问题都可以通过这些方法来解决。

如前所述,这些方法应用了一些伟大的概念,但显然,它不是最快的,也不是很长时间的,也不是任何合理的措施。而且,这完全取决于你所追求的准确性。据我所知,最快的π是数字硬编码的π。看看和,有很多公式

这里有一种快速收敛的方法——每次迭代大约14位,当前最快的应用程序,将此公式与FFT结合使用。我将只编写公式,因为代码很简单。这个公式几乎是由科学家发现的。这实际上是他如何计算出这个数字的数十亿位数——所以这不是一个可以忽略的方法。公式将很快溢出,而且,由于我们正在划分阶乘,因此推迟此类计算以删除项将是有利的

在哪里,

下面是一个例子。维基百科提到,当ab足够接近时,(a+b)²/4t将是π的近似值。我不确定“足够接近”是什么意思,但从我的测试来看,一次迭代得到2位数,两次得到7位数,三次得到15位数,当然这是双精度的,所以根据它的表示,它可能有一个错误,真实的计算可能更准确

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)
最后,来点pi高尔夫(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);}

如果您所说的“最快”是指输入代码最快,那么以下是解决方案:

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;

;“”6666,-2%{2+.2/@*\/10.3±2*+}*`1000实际上有一整本书(除其他外)专门介绍了计算π的快速方法:乔纳森和彼得·博文(Jonathan and Peter Borwein)()的《π与年度股东大会》

我研究了AGM和相关的算法很多:它很有趣(虽然有时不平凡)

请注意,要实现大多数现代算法来计算\pi,您将需要一个多精度算术库(is q
;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}
/* Return approximation of n * PI; n is integer */
#define pi_times(n) (((n) * 22) / 7)
PI = 3.141592654
4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))
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.
import math
print math.pi
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
import math
print math.acos(-1)
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
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))
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
/*
    Chudnovsky algorithm for computing PI
*/

#include <iostream>
#include <cmath>
using namespace std;

double calc_PI(int K=2) {

    static const int A = 545140134;
    static const int B = 13591409;
    static const int D = 640320;

    const double ID3 = 1./ (double(D)*double(D)*double(D));

    double sum = 0.;
    double b   = sqrt(ID3);
    long long int p = 1;
    long long int a = B;

    sum += double(p) * double(a)* b;

    // 2 iterations enough for double convergence
    for (int k=1; k<K; ++k) {
        // A*k + B
        a += A;
        // update denominator
        b *= ID3;
        // p = (-1)^k 6k! / 3k! k!^3
        p *= (6*k)*(6*k-1)*(6*k-2)*(6*k-3)*(6*k-4)*(6*k-5);
        p /= (3*k)*(3*k-1)*(3*k-2) * k*k*k;
        p = -p;

        sum += double(p) * double(a)* b;
    }

    return 1./(12*sum);
}

int main() {

    cout.precision(16);
    cout.setf(ios::fixed);

    for (int k=1; k<=5; ++k) cout << "k = " << k << "   PI = " << calc_PI(k) << endl;

    return 0;
}
k = 1   PI = 3.1415926535897341
k = 2   PI = 3.1415926535897931
k = 3   PI = 3.1415926535897931
k = 4   PI = 3.1415926535897931
k = 5   PI = 3.1415926535897931
#include <stdio.h>
#include <math.h>

double calc_PI(int K) {
    static const int A = 545140134;
    static const int B = 13591409;
    static const int D = 640320;
    const double ID3 = 1.0 / ((double) D * (double) D * (double) D);
    double sum = 0.0;
    double b = sqrt(ID3);
    long long int p = 1;
    long long int a = B;
    sum += (double) p * (double) a * b;
    for (int k = 1; k < K; ++k) {
        a += A;
        b *= ID3;
        p *= (6 * k) * (6 * k - 1) * (6 * k - 2) * (6 * k - 3) * (6 * k - 4) * (6 * k - 5);
        p /= (3 * k) * (3 * k - 1) * (3 * k - 2) * k * k * k;
        p = -p;
        sum += (double) p * (double) a * b;
    }
    return 1.0 / (12 * sum);
}

int main() {
    for (int k = 1; k <= 5; ++k) {
        printf("k = %i, PI = %.16f\n", k, calc_PI(k));
    }
}