代码之家  ›  专栏  ›  技术社区  ›  C. K. Young

获得价值的最快方法是什么?

  •  304
  • C. K. Young  · 技术社区  · 16 年前

    作为一项个人挑战,我正在寻找最快的方法来获得价值。更具体地说,我使用的方法不涉及使用 #define 常数类 M_PI 或硬编码。

    下面的程序测试了我所知道的各种方法。从理论上讲,内联汇编版本是最快的选择,但显然不可移植。我把它作为比较其他版本的基准。在我的测试中,内置的 4 * atan(1) 版本在GCC4.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) 每一次版本仍然是最流行的。

    23 回复  |  直到 6 年前
        1
  •  196
  •   Tyfingr    6 年前

    这个 Monte Carlo method 如前所述,应用了一些伟大的概念,但显然,它不是最快的,不是一个远射,不是任何合理的措施。而且,这一切都取决于你在寻找什么样的准确度。我所知道的最快的数字是硬编码的。看着 Pi Pi[PDF] 有很多公式。

    这里有一种方法,每次迭代可快速收敛约14位数字。 PiFast 是当前速度最快的应用程序,将此公式与FFT一起使用。我只写公式,因为代码很简单。这个公式几乎是由 Ramanujan and discovered by Chudnovsky . 这实际上是他如何计算出这个数字的几十亿位,所以这不是一个可以忽略的方法。这个公式会很快溢出,因为我们在除阶乘,所以延迟计算以删除项是有利的。

    enter image description here

    enter image description here

    哪里,

    enter image description here

    下面是 Brent–Salamin algorithm . 维基百科提到 那么“足够近了” (a+b)/4t 将是的近似值。我不知道“足够接近”是什么意思,但是从我的测试来看,一次迭代有两位数,两个得到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)
    

    最后,来点皮球(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);}
    
        2
  •  110
  •   Jack Bashford    6 年前

    我真的很喜欢这个程序,因为它通过观察自己的区域来近似。

    IOCC 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()
    {
                _-_-_-_
           _-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_-_-_-_-_
      _-_-_-_-_-_-_-_-_-_-_-_-_-_
     _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
     _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
     _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
     _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
      _-_-_-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_-_-_-_-_
            _-_-_-_-_-_-_-_
                _-_-_-_
    }
    
        3
  •  76
  •   Peter Mortensen icecrime    12 年前

    这是我高中时学过的一种计算圆周率的方法的一般描述。

    我只分享这一点,因为我认为它足够简单,任何人都可以无限期地记住它,而且它教给你“蒙特卡洛”方法的概念——这是获得答案的统计方法,似乎不能立即通过随机过程推导出来。

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

    现在把飞镖扔到广场上,记录它落在哪里——也就是说,在广场内的任何地方选择一个随机点。当然,它降落在正方形内,但它是在半圆形内吗?记录下这个事实。

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

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

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

        4
  •  54
  •   jon hanson    6 年前

    为了实现完整性,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个迭代,我相信有大约80k个对value()的调用(在没有Memoisation的情况下)。

        5
  •  42
  •   vdbuilder    13 年前

    实际上有一整本书都致力于 快速的 Jonathan和Peter Borwein的“pi和agm”的计算方法( available on Amazon )

    我研究了很多AGM和相关的算法:它很有趣(尽管有时很重要)。

    注意,要实现大多数现代算法来计算\pi,您需要一个多精度算法库( GMP 是个不错的选择,虽然我上次使用它已经有一段时间了)。

    最佳算法的时间复杂度以o(m(n)log(n))表示,其中m(n)是使用基于fft的算法将两个n位整数(m(n)=o(n)log(n))相乘的时间复杂度,这通常是在计算\pi的位数时需要的,并且这种算法在gmp中实现。

    请注意,尽管算法背后的数学可能并不简单,但算法本身通常是几行伪代码,它们的实现通常非常简单(如果您选择不编写自己的多精度算法:-)。

        6
  •  40
  •   Tilo    6 年前

    以下答案 准确地说,如何以尽可能快的方式做到这一点——用最少的计算工作量 . 即使你不喜欢这个答案,你也必须承认它确实是获得π值的最快方法。

    这个 最快的 获取pi值的方法是:

    1)选择您最喜欢的编程语言 2)加载其数学库 3)并且发现pi已经在那里定义了——准备好使用了!

    万一你手头没有数学图书馆……

    这个 第二快 方法(更普遍的解决方案)是:

    在Internet上查找pi,例如:

    http://www.eveandersson.com/pi/digits/1000000 (100万位)你的浮点精度是多少?)

    或在这里:

    http://3.141592653589793238462643383279502884197169399375105820974944592.com/

    或在这里:

    http://en.wikipedia.org/wiki/Pi

    无论您想使用什么精度的算术,找到所需的数字都是非常快的,通过定义一个常量,您可以确保不会浪费宝贵的CPU时间。

    这不仅是一个部分幽默的答案,而且在现实中,如果有人继续计算π在实际应用中的价值的话。那将是对CPU时间的极大浪费,不是吗?至少我没有看到一个真正的应用程序试图重新计算这个。

    尊敬的主持人:请注意,OP要求:“获取pi值的最快方法”

        7
  •  26
  •   Tyler    16 年前

    这个 BBP formula 允许您以2(或16)为基数计算第n个数字,而不必先考虑前面的n-1个数字:)

        8
  •  22
  •   Peter Mortensen icecrime    12 年前

    我不把π定义为常量,而是使用 acos(-1) .

        9
  •  21
  •   C. K. Young    16 年前

    刚刚遇到了一个完整性应该在这里的问题:

    calculate PI in Piet

    它有一个相当好的特性,可以提高精度,使程序更大。

    Here 对语言本身的一些洞察

        10
  •  21
  •   Mark Cooper    15 年前

    如果 this article 是真的,那么 algorithm that Bellard 创造可能是最快的。他用台式电脑创造了2.7万亿个圆周率!

    …他已经发表了他的 work here

    干得好,贝拉德,你是个先锋!

    http://www.theregister.co.uk/2010/01/06/very_long_pi/

        11
  •  20
  •   phuclv    6 年前

    这是一个“经典”的方法,非常容易实现。 这个实现是用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)
    

    你可以找到更多的信息 here .

    无论如何,在python中获得精确的pi值的最快方法是:

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

    编辑: 我对剪切粘贴和识别有点问题,不管怎样你都能找到来源。 here .

        12
  •  19
  •   Michiel de Mare    16 年前

    如果说“最快”是指输入代码最快,那么下面是 golfscript 解决方案:

    ;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
    
        13
  •  17
  •   animuson    13 年前

    使用类似机器的公式

    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 (atan (/ 1 57))) (* 28 (atan (/ 1 239)))) (* 48 (atan (/ 1 682)))) (* 96 (atan (/ 1 12943))))

        14
  •  16
  •   Daniel C. Sobral    15 年前

    如果你愿意使用近似值, 355 / 113 适用于6位十进制数字,并具有可用于整数表达式的附加优势。这并不像“浮点数学协处理器”那样重要,但它曾经非常重要。

        15
  •  15
  •   Peter Mortensen icecrime    12 年前

    双打:

    4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))
    

    这将精确到小数点后14位,足以填充一个双精度(不精确可能是因为弧切线中的其余小数被截断)。

    还有塞思,是3.14159265358979323846 不是64。

        16
  •  15
  •   Brad Gilbert    12 年前

    用d计算编译时的pi。

    (抄袭) 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))) );
    
        17
  •  15
  •   phuclv    6 年前

    圆周率正好是3![弗里克教授(辛普森一家)]

    开玩笑,但这里有一个C(.NET框架是必需的)。

    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;
            }
        }
    }
    
        18
  •  13
  •   phuclv    6 年前

    这个版本(在Delphi中)没有什么特别的,但它至少比 the version Nick Hodge posted on his blog :)在我的机器上,大约需要16秒来进行10亿次迭代,得到的值为 三点一四一五九二六五 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.
    
        19
  •  12
  •   Kristopher Johnson    16 年前

    在过去的日子里,我们使用小单词大小和缓慢或不存在的浮点运算,我们经常这样做:

    /* Return approximation of n * PI; n is integer */
    #define pi_times(n) (((n) * 22) / 7)
    

    对于不需要太高精度的应用程序(例如,视频游戏),这是非常快的,并且足够精确。

        20
  •  12
  •   Seth    15 年前

    如果你想 计算 值的近似值(出于某种原因),您应该尝试使用二进制提取算法。 Bellard's 改进 BBP 给出圆周率o(n^2)。


    如果你想 获得 待计算值的近似值,然后:

    PI = 3.141592654
    

    当然,这只是一个近似值,并不完全准确。它关闭了0.00000000004102多一点。(四个十万亿分之一,大约 / 一百亿 )


    如果你想的话 数学 用,然后给你自己拿一支铅笔和一张纸或者一个计算机代数包,然后用它的确切值。

    如果你真的想要一个公式,这个很有趣:

    = LN(- 1)

        21
  •  11
  •   James Youngman    15 年前

    上面克里斯发布的布伦特方法非常好;布伦特通常是任意精度算术领域的巨人。

    如果你只想要第n个数字,著名的 BBP formula 十六进制有用

        22
  •  1
  •   Agnius Vasiliauskas    7 年前

    从圆面积计算:—)

    <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 += "&nbsp;" 
            }
            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>
        23
  •  0
  •   Anand Tripathi    6 年前

    更好的方法

    获取标准常量的输出,例如 圆周率 或者是标准概念,我们首先应该使用内置方法,即您使用的语言。它将以最快和最好的方式返回值。我正在使用python获取获取值pi的最快方法

    • 数学库的pi变量 . 数学库将变量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
    
    • 使用弧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
    

    BBPIPI.Py

    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