The का मान प्राप्त करने का सबसे तेज़ तरीका क्या है?


322

मैं व्यक्तिगत चुनौती के रूप में as का मान प्राप्त करने का सबसे तेज़ तरीका खोज रहा हूं। अधिक विशेष रूप से, मैं ऐसे तरीकों का उपयोग कर रहा हूं, जिनमें #defineनिरंतरता का उपयोग करना शामिल नहीं है M_PI, या संख्या को हार्ड-कोडिंग करना शामिल है।

नीचे दिया गया कार्यक्रम उन विभिन्न तरीकों का परीक्षण करता है जिनके बारे में मुझे पता है। इनलाइन असेंबली संस्करण, सिद्धांत रूप में, सबसे तेज़ विकल्प है, हालांकि स्पष्ट रूप से पोर्टेबल नहीं है। मैंने इसे अन्य संस्करणों के मुकाबले तुलना करने के लिए आधार रेखा के रूप में शामिल किया है। बिल्ट-इन के साथ मेरे परीक्षणों में, 4 * atan(1)संस्करण जीसीसी 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

विभिन्न संकलक झंडों के बीच परीक्षण के अलावा (मैंने 64-बिट के मुकाबले 32-बिट की तुलना की है, क्योंकि अनुकूलन अलग-अलग हैं), मैंने परीक्षणों के क्रम को बदलने की भी कोशिश की है। लेकिन फिर भी, atan2(0, -1)संस्करण अभी भी हर बार शीर्ष पर आता है।


38
C ++ मेटाप्रोग्रामिंग में इसे करने का एक तरीका होना चाहिए। रन समय वास्तव में अच्छा होगा, लेकिन संकलन समय नहीं होगा।
डेविड थॉर्नले

1
आप एमन (1) को एम_पीआई के उपयोग से अलग क्यों मानते हैं? मैं समझ सकता हूं कि आप ऐसा क्यों करना चाहते हैं यदि आप केवल अंकगणित संचालन का उपयोग करते हैं, लेकिन अतन के साथ मैं बिंदु नहीं देखता हूं।
एरिक्कलेन 12

9
सवाल यह है: आप एक निरंतर उपयोग क्यों नहीं करना चाहेंगे? उदाहरण के लिए या तो एक पुस्तकालय या अपने आप से परिभाषित? कम्प्यूटिंग पाई सीपीयू चक्रों की बर्बादी है, क्योंकि यह समस्या दैनिक गणनाओं के लिए जरूरत से ज्यादा महत्वपूर्ण अंकों की संख्या से अधिक से अधिक बार-बार हल की गई है
टिलो

2
@ HopelessN00b अंग्रेजी मैं बात, "अनुकूलन" की बोली में है की वर्तनी एक "एस", नहीं एक "Z" (यह "जेड", Btw, नहीं "ज़ी" ;-) स्पष्ट है) के साथ। (यह पहली बार नहीं है जब मुझे इस तरह के संपादन को वापस करना पड़ा है, यदि आप समीक्षा इतिहास को देखें तो भी।)
क्रिस जैस्टर-यंग

जवाबों:


205

मोंटे कार्लो विधि , के रूप में उल्लेख किया है, कुछ महान अवधारणाओं,, लागू होता है, लेकिन यह है, स्पष्ट रूप से सबसे तेजी से नहीं, एक लंबे शॉट से नहीं किसी भी उचित उपाय से नहीं। इसके अलावा, यह सब इस बात पर निर्भर करता है कि आप किस तरह की सटीकता की तलाश कर रहे हैं। सबसे तेज़ know मुझे पता है कि अंकों के साथ कठिन कोडित है। को देखते हुए पाई और पाई [PDF] , वहाँ सूत्रों के एक बहुत हैं।

यहां एक विधि है जो जल्दी से रूपांतरित होती है - लगभग 14 अंक प्रति पुनरावृत्ति। मौजूदा सबसे तेज़ एप्लिकेशन PiFast , FFT के साथ इस सूत्र का उपयोग करता है। मैं केवल सूत्र लिखूंगा, क्योंकि कोड सीधा है। यह सूत्र लगभग रामानुजन द्वारा खोजा गया था और चुडनोवस्की द्वारा खोजा गया था । यह वास्तव में है कि कैसे उन्होंने संख्या के कई अरब अंकों की गणना की - इसलिए यह उपेक्षा करने का एक तरीका नहीं है। सूत्र जल्दी से अतिप्रवाह होगा और, चूंकि हम भाज्य को विभाजित कर रहे हैं, इसलिए ऐसे शब्दों को हटाने के लिए देरी करना लाभप्रद होगा।

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

कहाँ पे,

यहां छवि विवरण दर्ज करें

नीचे ब्रेंट-सेलमिन एल्गोरिथ्म है । विकिपीडिया कहा गया है कि जब एक और b "करीब पर्याप्त" होते हैं तब (a + b) t / 4t ation का एक अनुमान होगा। मुझे यकीन नहीं है कि "करीब पर्याप्त" का क्या मतलब है, लेकिन मेरे परीक्षणों से, एक पुनरावृत्ति को 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)

अंत में, कैसे कुछ पाई गोल्फ (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);}

1
यह मानते हुए कि आप पहले स्वयं को लागू करने की कोशिश कर रहे हैं, वर्ग (k3) समस्या नहीं होगी? मुझे पूरा यकीन है कि यह एक अपरिमेय संख्या को समाप्त कर देगा जिसे आपको अनुमान लगाना होगा (IIRC, सभी जड़ें जो पूरी संख्या नहीं हैं, अपरिमेय है)। यदि आप अनंत परिशुद्धता अंकगणित का उपयोग कर रहे हैं, तो बाकी सब कुछ बहुत सीधा-सा लगता है, लेकिन यह वर्ग रूट एक डील ब्रेकर है। दूसरे में एक sqrt भी शामिल है।
बिल के

2
मेरे अनुभव में, 'काफी पास' का मतलब आमतौर पर एक टेलर श्रृंखला सन्निकटन शामिल है।
स्टीफन

117

मैं वास्तव में इस कार्यक्रम को पसंद करता हूं, क्योंकि यह अपने क्षेत्र को देखकर, अनुमान लगाता है।

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()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

1
यदि आप _ के साथ -F <00 || --F-OO-- का अनुसरण करते हैं, तो :-) का पालन करना आसान होना चाहिए
Pat

1
या, यदि आप _ को "if (पिछला वर्ण '-') {OO--;} F--" से प्रतिस्थापित करते हैं
फ्राईग्यु

6
यह 0.25 यहाँ प्रिंट करता है।
जोहान्स स्काउब -

8
यह कार्यक्रम 1998 में बहुत अच्छा था, लेकिन टूट गया था क्योंकि आधुनिक प्रीप्रोसेसर इस तरह की चीजों को काम करने से रोकने के लिए मैक्रो विस्तार के आसपास रिक्त स्थान डालने के साथ अधिक उदार हैं। यह एक दुर्भाग्य है।
क्रिस लुट्ज़

38
इच्छित व्यवहार प्राप्त करने के --traditional-cppलिए सीपीपी पास करें ।
नीत्शे-जौ

78

यहाँ उच्च विद्यालय में सीखी गई पीआई की गणना के लिए एक तकनीक का सामान्य विवरण दिया गया है।

मैं इसे केवल इसलिए साझा करता हूं क्योंकि मुझे लगता है कि यह काफी सरल है कि कोई भी इसे अनिश्चित काल तक याद रख सकता है, साथ ही यह आपको "मोंटे-कार्लो" विधियों की अवधारणा भी सिखाता है - जो उत्तर देने के सांख्यिकीय तरीके हैं जो तुरंत दिखाई नहीं देते हैं यादृच्छिक प्रक्रियाओं के माध्यम से समर्पण।

एक वर्ग ड्रा करें, और उस वर्ग के अंदर एक चतुर्भुज (अर्ध-वृत्त का एक चौथाई) लिखें (वर्ग के किनारे के बराबर त्रिज्या वाला चतुर्थांश, इसलिए यह वर्ग के जितना संभव हो उतना भरता है)

अब एक डार्ट को वर्ग में फेंकें, और रिकॉर्ड करें कि यह कहाँ है - यानी वर्ग के अंदर कहीं भी एक यादृच्छिक बिंदु चुनें। बेशक, यह वर्ग के अंदर उतरा, लेकिन क्या यह अर्ध-चक्र के अंदर है? इस तथ्य को रिकॉर्ड करें।

इस प्रक्रिया को कई बार दोहराएं - और आप पाएंगे कि सेमी-सर्कल के अंदर अंकों की संख्या का अनुपात है जो कुल संख्या में फेंक दिया गया है, इस अनुपात को x कहें।

चूँकि वर्ग का क्षेत्रफल r टाइम्स r है, आप यह मान सकते हैं कि अर्ध वृत्त का क्षेत्रफल x गुणा r गुणा r है (अर्थात x गुणा r वर्ग)। इसलिए x 4 बार आपको pi देगा।

यह उपयोग करने के लिए एक त्वरित विधि नहीं है। लेकिन यह मोंटे कार्लो पद्धति का एक अच्छा उदाहरण है। और यदि आप चारों ओर देखते हैं, तो आप पा सकते हैं कि कई समस्याएं अन्यथा आपके कम्प्यूटेशनल कौशल के बाहर ऐसे तरीकों से हल की जा सकती हैं।


2
यह वह विधि है जिसका उपयोग हमने स्कूल में एक जावा परियोजना में पाई की गणना के लिए किया था। बस x, y निर्देशांक और अधिक 'डार्ट्स' के साथ आने के लिए एक रैंडमाइज़र का उपयोग किया, जिसे हमने पीए के करीब लाया।
जेफ केसलिंक

55

पूर्णता के हितों में, एक सी ++ टेम्पलेट संस्करण, जो एक अनुकूलित बिल्ड के लिए, संकलन समय पर पीआई का एक अनुमान लगाएगा, और एक मूल्य पर इनलाइन करेगा।

#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 कॉल हैं (स्मरण के अभाव में)।


मैं इसे चलाता हूं और "पीआई ~ 3.14159265383" प्राप्त करता
हूं

5
खैर, यह 9dp के लिए सटीक है। क्या आप किसी चीज़ पर आपत्ति कर रहे हैं या सिर्फ एक अवलोकन कर रहे हैं?
जॉन-हॉनसन

पीआई की गणना करने के लिए यहां उपयोग किए जाने वाले एल्गोरिथ्म का नाम क्या है?
सेबस्टीओ मिरांडा

1
@ sebastião-miranda Leibniz का सूत्र , औसत त्वरण में सुधार के साथ अभिसरण। pi_calc<0, J>सूत्र से प्रत्येक क्रमिक शब्द की गणना करता है और गैर-विशिष्ट pi_calc<I, J>औसत की गणना करता है।
जौन-हैंसन 18

43

जोनाथन और पीटर बोरवेइन ( अमेज़न पर उपलब्ध ): पीआई की गणना के लिए फास्ट तरीकों के लिए वास्तव में एक पूरी किताब समर्पित है (अन्य चीजों के अलावा) : 'पाई और एजीएम'। ) ।

मैंने एजीएम और संबंधित एल्गोरिदम का काफी अध्ययन किया: यह काफी दिलचस्प है (हालांकि कभी-कभी गैर-तुच्छ)।

ध्यान दें कि गणना करने के लिए अधिकांश आधुनिक एल्गोरिदम को लागू करने के लिए, आपको एक मल्टीपरपस अंकगणितीय लाइब्रेरी ( GMP) की आवश्यकता होगी काफी अच्छा विकल्प है, हालांकि यह थोड़ी देर के लिए है क्योंकि मैंने आखिरी बार इसका इस्तेमाल किया था)।

सर्वश्रेष्ठ एल्गोरिदम की समय-जटिलता O (M (n) लॉग (n)) में है, जहाँ M (n) दो n-बिट पूर्णांक (M (n) = O (n) के गुणन के लिए समय-जटिलता है लॉग (एन) लॉग (लॉग (एन)) एफएफटी-आधारित एल्गोरिदम का उपयोग करते हुए, जो आमतौर पर \ _ पाई के कंप्यूटिंग अंकों की आवश्यकता होती है, और इस तरह के एक एल्गोरिथ्म को जीएमपी में लागू किया जाता है)।

ध्यान दें कि भले ही एल्गोरिदम के पीछे का गणित तुच्छ नहीं हो सकता है, एल्गोरिदम स्वयं आमतौर पर छद्म कोड की कुछ पंक्तियाँ हैं, और उनका कार्यान्वयन आमतौर पर बहुत सीधा होता है (यदि आपने अपना मल्टीप्रेशर अंकगणितीय :-) लिखना नहीं चुना है)।


42

निम्नलिखित उत्तर सटीक रूप से सबसे तेज़ संभव तरीके से यह करने के लिए - कम से कम कंप्यूटिंग प्रयास के साथ । यहां तक ​​कि अगर आपको जवाब पसंद नहीं है, तो आपको यह स्वीकार करना होगा कि यह वास्तव में पीआई का मूल्य पाने का सबसे तेज़ तरीका है।

पाई का मान पाने का सबसे आसान तरीका है:

1) अपनी पसंदीदा प्रोग्रामिंग भाषा को चुना 2) अपनी गणित लाइब्रेरी को 3 लोड करें) और पाएं कि पाई पहले से ही वहां परिभाषित है - उपयोग के लिए तैयार!

मामले में आप हाथ में एक मठ पुस्तकालय नहीं है ..

दूसरा सबसे तेज रास्ता (अधिक सार्वभौमिक समाधान) है:

इंटरनेट पर पाई को देखें, जैसे यहाँ:

http://www.eveandersson.com/pi/digits/1000000 (1 मिलियन अंक .. आपकी फ्लोटिंग पॉइंट परिशुद्धता क्या है?)

या इधर:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

या इधर:

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

यह वास्तव में तेज़ है कि आपको जो भी सटीक अंकगणित का उपयोग करना है, उसके लिए आपके द्वारा आवश्यक अंकों को खोजना होगा, और एक स्थिरांक को परिभाषित करके, आप यह सुनिश्चित कर सकते हैं कि आप कीमती सीपीयू समय बर्बाद नहीं करते हैं।

न केवल यह एक आंशिक रूप से विनोदी उत्तर है, लेकिन वास्तव में, यदि कोई आगे बढ़ेगा और वास्तविक अनुप्रयोग में पाई के मूल्य की गणना करेगा .. तो यह सीपीयू समय का एक बहुत बड़ा बेकार होगा, है ना? कम से कम मुझे इसे पुनः गणना करने की कोशिश के लिए एक वास्तविक एप्लिकेशन नहीं दिखता है।

प्रिय मॉडरेटर: कृपया ध्यान दें कि ओपी ने पूछा: "पीआई का मूल्य प्राप्त करने का सबसे तेज़ तरीका"


प्रिय तिलो: कृपया ध्यान दें कि ओपी ने कहा: "मैं व्यक्तिगत चुनौती के रूप में π का ​​मूल्य प्राप्त करने का सबसे तेज़ तरीका ढूंढ रहा हूं। अधिक विशेष रूप से, मैं ऐसे तरीकों का उपयोग कर रहा हूं जिनमें M_PI जैसे #define स्थिरांक का उपयोग करना शामिल नहीं है। , या हार्ड-कोडिंग में संख्या
अधिकतम

प्रिय @ मोम: कृपया ध्यान दें कि ओपी ने अपने मूल प्रश्न का उत्तर दिया जब मैंने इसका उत्तर दिया - यह शायद ही मेरी गलती है;) मेरा समाधान अभी भी सबसे तेज़ तरीका है, और किसी भी वांछित फ़्लोटिंग पॉइंट परिशुद्धता के साथ समस्या को हल करता है और कोई सीपीयू साइकिल सुरुचिपूर्ण ढंग से :)
Tilo

क्षमा करें, मुझे एहसास नहीं हुआ। बस एक विचार, कठिन कोडित स्थिरांक पी की गणना की तुलना में कम सटीकता नहीं है? मुझे लगता है कि यह इस बात पर निर्भर करता है कि यह किस भाषा में है और रचनाकार सभी अंकों को :-) में रखने के लिए कितना इच्छुक है
अधिकतम

1
लानत है मैं प्रिय तिलो
मैक्स

27

BBP सूत्र आधार 2 (या 16) में - - आप वें अंकों की गणना करने के लिए अनुमति देता है यहां तक कि पहले पिछले n-1 अंकों के साथ परेशान करने के लिए बिना :)


23

एक स्थिर के रूप में पाई को परिभाषित करने के बजाय, मैं हमेशा उपयोग करता हूं acos(-1)


2
cos (-1), या acos (-1)? :-P वह (बाद वाला) मेरे मूल कोड में परीक्षण मामलों में से एक है। यह मेरे पसंदीदा (atan2 (0, -1) के साथ है, जो वास्तव में acos (-1) के समान है, सिवाय इसके कि acos आमतौर पर atan2 के संदर्भ में लागू होता है), लेकिन कुछ कंपाइलर 4 * atan (1) के लिए अनुकूलित करते हैं !
क्रिस जस्टर-यंग

21

यह एक "क्लासिक" विधि है, जिसे लागू करना बहुत आसान है। अजगर में यह कार्यान्वयन (सबसे तेज भाषा नहीं) करता है:

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 "Constant pi: %.40f" % pi
print "Difference: %.40f" % abs(calc-pi)
print "Time elapsed: %s" % repr(t)

आप अधिक जानकारी यहाँ पा सकते हैं ।

वैसे भी, अजगर में पाई के मूल्य के रूप में एक सटीक के रूप में एक बहुत पाने के लिए सबसे तेज़ तरीका है:

from gmpy import pi
print pi(3000) # the rule is the same as 
               # the precision on the previous code

यहाँ पेपी विधि के लिए स्रोत का एक टुकड़ा है, मुझे नहीं लगता कि कोड इस मामले में टिप्पणी के रूप में उपयोगी है:

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

संपादित करें: मुझे कट और पेस्ट और इंडेंटेशन के साथ कुछ समस्याएं थीं, आप यहां स्रोत पा सकते हैं ।



18

यदि आप एक सन्निकटन का उपयोग करने के इच्छुक हैं, 355 / 113तो 6 दशमलव अंकों के लिए अच्छा है, और पूर्णांक अभिव्यक्तियों के साथ प्रयोग करने योग्य होने का अतिरिक्त लाभ है। यह इन दिनों उतना महत्वपूर्ण नहीं है, जितना कि "फ्लोटिंग पॉइंट मैथ सह-प्रोसेसर" का कोई मतलब नहीं है, लेकिन यह एक बार काफी महत्वपूर्ण था।


18

माचिन जैसे सूत्र का उपयोग करें

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


16

युगल के साथ:

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

यह 14 दशमलव स्थानों तक सटीक होगा, एक डबल भरने के लिए पर्याप्त (अशुद्धि शायद इसलिए है क्योंकि चाप स्पर्शरेखा में बाकी दशमलवों को छोटा कर दिया जाता है)।

इसके अलावा, सेठ, यह 3.14159265358979323846 3 है , 64 नहीं।


16

पाई बिल्कुल 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;
        }
    }
}

15

डी के साथ संकलन-समय पर पीआई की गणना करें।

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

2
दुर्भाग्य से, स्पर्शरेखा आर्कटिक हैं पीआई पर आधारित हैं, कुछ हद तक इस गणना को अमान्य करते हैं।
ग्रांट जॉनसन

14

यह संस्करण (डेल्फी में) कुछ खास नहीं है, लेकिन यह कम से कम अपने ब्लॉग पर पोस्ट किए गए संस्करण निक हॉज से अधिक तेज है :)। मेरी मशीन पर, एक अरब पुनरावृत्तियों को करने में लगभग 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.

13

पुराने दिनों में वापस, छोटे शब्द आकार और धीमी गति से या गैर-मौजूद फ्लोटिंग-पॉइंट ऑपरेशनों के साथ, हम इस तरह से सामान बनाते थे:

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

ऐसे अनुप्रयोगों के लिए जिन्हें बहुत अधिक सटीकता की आवश्यकता नहीं होती है (उदाहरण के लिए वीडियो गेम), यह बहुत तेज़ है और काफी सटीक है।


11
अधिक सटीकता के लिए उपयोग करें 355 / 113। शामिल संख्याओं के आकार के लिए बहुत सटीक है।
डेविड थॉर्नले

: बस जिज्ञासा से बाहर 22/7 है3 + 1/7
Agnius Vasiliauskas

13

यदि आप ) (किसी कारण से) के मूल्य के एक अनुमान की गणना करना चाहते हैं , तो आपको एक द्विआधारी निष्कर्षण एल्गोरिथ्म का प्रयास करना चाहिए। Bellard के के सुधार BBP हे (एन ^ 2) में पीआई करता है देता है।


यदि आप गणना करने के लिए do के मूल्य का एक अनुमान प्राप्त करना चाहते हैं , तो:

PI = 3.141592654

दी, यह केवल एक अनुमान है, और पूरी तरह से सटीक नहीं है। यह 0.00000000004102 से थोड़ा अधिक है। (चार दस-खरब, लगभग 4 / 10,000,000,000 )।


यदि आप you के साथ गणित करना चाहते हैं , तो अपने आप को एक पेंसिल और पेपर या एक कंप्यूटर बीजगणित पैकेज प्राप्त करें, और, के सटीक मूल्य, math का उपयोग करें।

यदि आप वास्तव में एक सूत्र चाहते हैं, तो यह मजेदार है:

π = - i ln (-1)


आपका सूत्र इस बात पर निर्भर करता है कि आप जटिल विमान में ln को कैसे परिभाषित करते हैं। यह जटिल विमान में एक पंक्ति के साथ गैर-सन्निहित होना चाहिए, और उस रेखा के लिए नकारात्मक वास्तविक अक्ष होना काफी सामान्य है।
एरिक्कलेन

12

ब्रेंट की क्रिस द्वारा पोस्ट की गई विधि बहुत अच्छी है; ब्रेंट आम तौर पर मनमानी-सटीक अंकगणित के क्षेत्र में एक विशालकाय है।

यदि आप चाहते हैं कि सभी Nth अंक है, तो प्रसिद्ध BBP सूत्र हेक्स में उपयोगी है


1
ब्रेंट विधि मेरे द्वारा पोस्ट नहीं की गई थी; यह एंड्रिया द्वारा पोस्ट किया गया था, और मैं सिर्फ आखिरी व्यक्ति था जिसने पोस्ट को संपादित किया। :-) लेकिन मैं सहमत हूँ, यह पद एक उत्थान का हकदार है।
क्रिस जस्टर-यंग

1

वृत्त क्षेत्र से π की गणना :-)

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


0

Chudnovsky एल्गोरिथ्म बहुत तेज है अगर आप एक वर्गमूल और एक जोड़े के प्रदर्शन का बुरा नहीं मानते। यह सिर्फ 2 पुनरावृत्तियों में दोहरी परिशुद्धता में परिवर्तित होता है।

/*
    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

0

बेहतर दृष्टिकोण

पाई या मानक अवधारणाओं जैसे मानक स्थिरांक का उत्पादन प्राप्त करने के लिए , हमें सबसे पहले उस भाषा में उपलब्ध तरीकों के साथ जाना चाहिए जिसे आप उपयोग कर रहे हैं। यह सबसे तेज और सबसे अच्छे तरीके से एक मूल्य लौटाएगा। मैं पाई का मान पाने के लिए सबसे तेज़ तरीका चलाने के लिए अजगर का उपयोग कर रहा हूं।

  • गणित पुस्तकालय के पीआई चर । गणित पुस्तकालय चर को स्थिर के रूप में संग्रहीत करता है।

math_pi.py

import math
print math.pi

लिनेक्स की समय उपयोगिता के साथ स्क्रिप्ट को चलाएं /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
  • गणित के आर्क कॉस विधि का उपयोग करें

acos_pi.py

import math
print math.acos(-1)

लिनेक्स की समय उपयोगिता के साथ स्क्रिप्ट को चलाएं /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_pi.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))

लिनेक्स की समय उपयोगिता के साथ स्क्रिप्ट को चलाएं /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

तो सबसे अच्छा तरीका भाषा द्वारा प्रदान किए गए अंतर्निहित तरीकों का उपयोग करना है क्योंकि वे आउटपुट प्राप्त करने के लिए सबसे तेज़ और सबसे अच्छे हैं। अजगर में math.pi का उपयोग करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.