通过使用16位算术求序列来计算π时避免溢出? [英] Avoid Overflow when Calculating π by Evaluating a Series Using 16-bit Arithmetic?

查看:117
本文介绍了通过使用16位算术求序列来计算π时避免溢出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个计算π到1000位或更多的十进制数字的程序。



要练习低级编程,最终的程序很有趣将以汇编形式写在没有乘法或除法且仅执行16位加法的8位CPU上。为了简化实现,希望只能使用16位无符号整数运算,并使用迭代算法。 速度不是主要问题。快速乘法和除法不在此问题的范围内,因此也不要考虑这些问题。



在组装之前,我要我仍然试图找出台式计算机上C语言中的可用算法。到目前为止,我发现以下序列是相当有效的,并且相对易于实现。



该公式是使用收敛加速技术To从莱布尼兹级数推导的派生它,请参见Carl D. Offner(



如果计算使用许多(例如5000个)项的序列,很容易获得数千位数的π,并且我发现使用该算法也很容易迭代评估该系列:



算法




  1. 首先,重新排列公式以从数组中获取其常数项。


  1. 用2填充数组以开始第一次迭代,因此t他的新公式类似于原始公式。


  2. 进位= 0


  3. 从最好的词开始。从数组中获得一项(2),将该项乘以 PRECISION 2 * i + 1 ,并将提醒作为新术语保存到数组中。然后添加下一项。现在递减 i ,转到下一项,重复直到 i == 1 。最后添加最后一项 x_0


  4. 因为使用了16位整数,所以 PRECISION 10 ,因此获得2个十进制数字,但只有第一位有效。将第二个数字另存为进位。显示第一个数字加进位。


  5. x_0 是整数2,不应为


  6. 转到第4步以计算下一个十进制数字,直到获得所需的所有数字为止。




实现1



将此算法转换为C:

  #include< stdio.h> 
#include< stdint.h>

#define N 2160
#define精度10

uint16_t条件[N +1] = {0};

int main(void)
{
/ *初始化初始项* /
for(size_t i = 0; i 个词[i] = 2;
}

uint16_t进位= 0;
for(size_t j = 0; j< N / 4; j ++){
uint16_t分子= 0;
uint16_t分母;
uint16_t位;

for(size_t i = N; i> 0; i--){
分子+ = term [i] *精度;
分母= 2 * i + 1;

项[i] =分子%分母;
分子/ =分母;
分子* = i;
}
分子+ =条件[0] *精度;
位=分子/精度+进位;
进位=分子%精度;

printf(%01u,数字);

/ *常数项2,仅在第一次迭代中需要。 * /
项[0] = 0;
}
putchar(’\n’);
}

代码可以计算π到31个十进制数字,直到出错为止。

  31415926535897932384626433832794 
10<-错误的

有时位数+进位大于9,因此需要额外的进位。如果我们很倒霉,甚至可能会有两次进位,三次进位等。我们使用环形缓冲区来存储最后4位数字。如果检测到多余的进位,我们将输出退格键以擦除前一位,执行进位并重新打印。这只是概念验证的丑陋解决方案,它与我关于溢出的问题无关,但是为了完整性,就在这里。



重复携带的实现2



  #include< stdio.h> 
#include< stdint.h>

#define N 2160
#define PRECISION 10

#define BUF_SIZE 4

uint16_t条件[N +1] = {0 };

int main(void)
{
/ *初始化初始项* /
for(size_t i = 0; i 个词[i] = 2;
}

uint16_t进位= 0;
uint16_t digit [BUF_SIZE];
int8_t idx = 0;

for(size_t j = 0; j< N / 4; j ++){
uint16_t分子= 0;
uint16_t分母;

for(size_t i = N; i> 0; i--){
分子+ = term [i] *精度;
分母= 2 * i + 1;

项[i] =分子%分母;
分子/ =分母;
分子* = i;
}
分子+ =条件[0] *精度;
digit [idx] =分子/精度+进位;

/ * 9岁以上,至少需要一个进位操作。 * /
if(digit [idx]> 9){
for(int i = 1; i< = 4; i ++){
if(i> 3){
/ *最多允许3个连续进位操作* /
fprintf(stderr,错误:进位操作太多!opn);
返回1;
}
/ *删除数字* /
putchar(’\b’);

/ *进位* /
digit [idx]-= 10;
idx--;
if(idx <0){
idx = BUF_SIZE-1;
}
digit [idx] ++;
if(digit [idx]< 10){
/ *完成!重新打印数字* /
for(int j = 0; j< = i; j ++){
printf(%01u,digit [idx]);
idx ++;
if(idx> BUF_SIZE-1){
idx = 0;
}
}
休息;
}
}
}
else {
printf(%01u,digit [idx]);
}

进位=分子%精度;
条件[0] = 0;

/ *将元素放入环形缓冲区* /
idx ++;
if(idx> BUF_SIZE-1){
idx = 0;
}
}
putchar(’\n’);
}

很好,现在程序可以正确计算534位π,直到
错误。

  3141592653589793238462643383279502884 
1971693993751058209749445923078164062
8620899862803482482534211706798214808651
3282306647093844609550582231725359408 b 1284811174502841027019385211055596446
2294895493038196442881097566593344612
8475648233786783165271201909145648566
9234603486104543266482133936072602491
4127372458700660631558817488152092096
2829254091715364367892590360011330530
5488204665213841469519415116094330572
7036575959195309218611738193261179310
5118548074462379962749567351885752724
8912279381830119491298336733624406566
43086021394946395
22421<-错误的



16位整数溢出



事实证明,在开始计算最大项时,由于t他一开始的除数在〜4000范围内。在评估序列时,分子实际上立即开始在乘法中溢出。



在计算时,整数溢出无关紧要前500位数字,但越来越差,直到给出错误的结果。



更改 uint16_t分子= 0 uint32_t分子= 0 可以解决此问题并计算π到1000+个数字。



但是,如前所述,我的目标平台是8位CPU,并且只有16位操作。是否仅使用一个或多个uint16_t 可以解决我在这里看到的16位整数溢出问题?如果无法避免使用多精度算术,那么在这里实现它的最简单方法是什么?我知道我需要引入一个额外的16位扩展字,但是我不确定该如何实现。



在此先感谢您的帮助。耐心地理解这里的长篇幅。

解决方案

看看相关的质量检查:






  • 已转换到固定点...

      // ----------------------------- ---------------------------------------------- 
    AnsiString str_hex2dec(const AnsiString& hex)
    {
    char c;
    AnsiString dec =,s;
    int i,j,l,ll,cy,val;
    int i0,i1,i2,i3,sig;
    sig = + 1; l = hex.Length();
    如果(l){c = hex [l];如果(c =='h')l--;如果(c =='H')l--; }
    i0 = 0; i1 = l; i2 = 0; i3 = l;
    for(i = 1; i <= l; i ++)//扫描数字
    {
    char c = hex [i];的部分
    if(c ==’-’)sig = -sig;
    if(((c ==’。’)|||(c ==’,’))i1 = i-1;
    if(((c> ='0')&&&&&&&(c< = 9')){如果((i0)i0 = i; if((!i2)&(i> i1))i2 = i; }
    if(((c> =’A’)&&&&&&&(c< = F))){if((i0)i0 = i; if((!i2)&(i> i1))i2 = i; }
    if(((c> =’a’)&&&&&&&&(c< = f))} {if((i0)i0 = i; if((!i2)&(i> i1))i2 = i; }
    }

    l = 0; s =; if(i0)for(i = i0; i< = i1; i ++)
    {
    c = hex [i];
    if(((c> ='0')&&(c< ='9'))c-='0';
    else if(((c> =’A’)&&(c< ='F’))c-=’A’-10;
    else if(((c> =’a’)&&(c< ='f’))c-=’A’-10;
    for(cy = c,j = 1; j <= l; j ++)
    {
    val =(s [j]< 4)+ cy;
    s [j] = val%10;
    cy = val / 10;
    }
    而(cy> 0)
    {
    l ++;
    s + = char(cy%10);
    cy / = 10;
    }
    }
    if(s!=)
    {
    for(j = 1; j< = l; j ++){c = s [j ];如果(c< 10)c + ='0';否则c + ='A'-10; s [j] = c; }
    for(i = l,j = 1; j< i; j ++,i--){c = s [i]; s [i] = s [j]; s [j] = c; }
    dec + = s;
    }
    if(dec ==)dec = 0;
    if(sig< 0)dec =- + dec;

    ,如果(i2)
    {
    dec + =’。’;
    s = hex.SubString(i2,i3-i2 + 1);
    l = s.Length(); (i = 1; i <= l; i ++)的

    {
    c = s [i];
    if(((c> ='0')&&(c< ='9'))c-='0';
    else if(((c> =’A’)&&(c< ='F’))c-=’A’-10;
    else if(((c> =’a’)&&(c< ='f’))c-=’A’-10;
    s [i] = c;
    }
    ll =((l * 1234)> 10); //计算(cy = 0,i = 1; i< = ll; i ++)的
    的小数位数
    {(cy = 0,j = l; j> = 1; j--)
    {
    val = s [j];
    val * = 10;
    val + = cy;
    s [j] = val& 15;
    cy = val>> 4;
    }
    dec + = char(cy +'0');
    for(;;)
    {
    if(!l)break ;;如果(s [l])中断,则

    l--;
    }
    如果(!l)中断;
    }
    }

    dec的回报;
    }
    // --------------------------------------- ------------------------------------
    AnsiString pi_BBP()// https:// en.wikipedia.org/wiki/Bailey–Borwein–Plouffe_formula
    {
    const int N = 100; // 32 * N位uint算术
    int sh;
    AnsiString s;
    uint< N> pi,a,b,k,k2,k3,k4; (pi = 0,sh =(N<< 5)-8,k = 0; sh> = 0; k ++,sh- = 4)的


    {
    k2 = k * k;
    k3 = k2 * k;
    k4 = k3 * k;
    a = k2 * 120;
    a + = k * 151;
    a + = 47;
    b = k4 * 512;
    b + = k3 * 1024;
    b + = k2 * 712;
    b + = k * 194;
    b + = 15;
    a<< = sh;
    pi + = a / b;
    }
    pi< == 4;
    s = pi.strhex();
    s = s.Insert(。,2);
    return str_hex2dec(s);
    }
    // --------------------------------------- ------------------------------------

    代码使用的是 VCL AnsiString ,它是一个自分配的字符串和我的 uint< N> 模板,它是基于我的 32 * N 位宽的无符号整数算法: //stackoverflow.com/a/26603589/2521214\">ALU32 。如您所见,您只需要为此进行大整数除法和乘法运算(所有其他内容对普通整数都是可行的)。



    这里是十进制结果与1000位Pi参考:

      ref:3。 113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989 
    BPP:3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771 30996051870721134999999837297804995105973173281601609631859502445945534690830264252230825334468503526193193817101000313783875288658753320320142061717766914730359825349042875546873115956286388235378759375195195195778778778778778187187上方链接中的c> str_hex2dec
    。迭代次数取决于目标位宽。



    代码尚未优化...


    I'm trying to write a program that calculates decimal digits of π to 1000 digits or more.

    To practice low-level programming for fun, the final program will be written in assembly, on a 8-bit CPU that has no multiplication or division, and only performs 16-bit additions. To ease the implementation, it's desirable to be able to use only 16-bit unsigned integer operations, and use an iterative algorithm. Speed is not a major concern. And fast multiplication and division is beyond the scope of this question, so don't consider those issues as well.

    Before implementing it in assembly, I'm still trying to figure out an usable algorithm in C on my desktop computer. So far, I found the following series is reasonably efficient and relatively easy to implement.

    The formula is derived from the Leibniz Series using a convergence acceleration technique, To derive it, see Computing the Digits in π, by Carl D. Offner (https://cs.umb.edu/~offner/files/pi.pdf), page 19-26. The final formula is shown in page 26. The initial formula I've written had some typos, please refresh the page to see the fixed formula. The constant term 2 at the greatest term is explained in page 54. The paper described an advanced iterative algorithm as well, but I didn't use it here.

    If one evaluates the series using many (e.g. 5000) terms, it's possible to get thousands digits of π easily, and I found this series is easy to evaluate iteratively as well using this algorithm:

    Algorithm

    1. First, rearrange the formula to obtain its constant terms from an array.

    1. Fill the array with 2 to start the first iteration, hence the new formula resembles the original one.

    2. Let carry = 0.

    3. Start from the greatest term. Obtain one term (2) from the array, multiply the term by PRECISION to perform a fixed-point division against 2 * i + 1, and save the reminder as the new term to the array. Then add the next term. Now decrement i, go to the next term, repeat until i == 1. Finally add the final term x_0.

    4. Because 16-bit integer is used, PRECISION is 10, hence 2 decimal digits are obtained, but only the first digit is valid. Save the second digit as carry. Show the first digit plus carry.

    5. x_0 is the integer 2, it should not be added for the successive iterations, clear it.

    6. Goto step 4 to calculate the next decimal digit, until we have all the digits we want.

    Implementation 1

    Translating this algorithm to C:

    #include <stdio.h>
    #include <stdint.h>
    
    #define N 2160
    #define PRECISION 10
    
    uint16_t terms[N + 1] = {0};
    
    int main(void)
    {
        /* initialize the initial terms */
        for (size_t i = 0; i < N + 1; i++) {
            terms[i] = 2;
        }
    
        uint16_t carry = 0;
        for (size_t j = 0; j < N / 4; j++) {
            uint16_t numerator = 0;
            uint16_t denominator;
            uint16_t digit;
    
            for (size_t i = N; i > 0; i--) {
                numerator += terms[i] * PRECISION;
                denominator = 2 * i + 1;
    
                terms[i] = numerator % denominator;
                numerator /= denominator;
                numerator *= i;
            }
            numerator += terms[0] * PRECISION;
            digit = numerator / PRECISION + carry;
            carry = numerator % PRECISION;
    
            printf("%01u", digit);
    
            /* constant term 2, only needed for the first iteration. */
            terms[0] = 0;
        }
        putchar('\n');
    }
    

    The code can calculate π to 31 decimal digits, until it makes an error.

    31415926535897932384626433832794
    10 <-- wrong
    

    Sometimes digit + carry is greater than 9, so it needs an extra carry. If we are very unlucky, there may even be a double carry, triple carry, etc. We use a ring-buffer to store the last 4 digits. If an extra carry is detected, we output a backspace to erase the previous digit, perform a carry, and reprint them. This is just a ugly solution to the Proof-of-Concept, which is irrelevant to my question about overflow, but for completeness, here is it. Something better would be implemented in the future.

    Implementation 2 with Repeated Carry

    #include <stdio.h>
    #include <stdint.h>
    
    #define N 2160
    #define PRECISION 10
    
    #define BUF_SIZE 4
    
    uint16_t terms[N + 1] = {0};
    
    int main(void)
    {
        /* initialize the initial terms */
        for (size_t i = 0; i < N + 1; i++) {
            terms[i] = 2;
        }
    
        uint16_t carry = 0;
        uint16_t digit[BUF_SIZE];
        int8_t idx = 0;
    
        for (size_t j = 0; j < N / 4; j++) {
            uint16_t numerator = 0;
            uint16_t denominator;
    
            for (size_t i = N; i > 0; i--) {
                numerator += terms[i] * PRECISION;
                denominator = 2 * i + 1;
    
                terms[i] = numerator % denominator;
                numerator /= denominator;
                numerator *= i;
            }
            numerator += terms[0] * PRECISION;
            digit[idx] = numerator / PRECISION + carry;
    
            /* over 9, needs at least one carry op. */
            if (digit[idx] > 9) {
                for (int i = 1; i <= 4; i++) {
                    if (i > 3) {
                        /* allow up to 3 consecutive carry ops */
                        fprintf(stderr, "ERROR: too many carry ops!\n");
                        return 1;
                    }
                    /* erase a digit */
                    putchar('\b');
    
                    /* carry */
                    digit[idx] -= 10;
                    idx--;
                    if (idx < 0) {
                        idx = BUF_SIZE - 1;
                    }
                    digit[idx]++;            
                    if (digit[idx] < 10) {
                        /* done! reprint the digits */
                        for (int j = 0; j <= i; j++) {
                            printf("%01u", digit[idx]);
                            idx++;
                            if (idx > BUF_SIZE - 1) {
                                idx = 0;
                            }
                        }
                        break;
                    }
                }
            }
            else {
                printf("%01u", digit[idx]);
            }
    
            carry = numerator % PRECISION;
            terms[0] = 0;
    
            /* put an element to the ring buffer */
            idx++;
            if (idx > BUF_SIZE - 1) {
                idx = 0;
            }
        }
        putchar('\n');
    }
    

    Great, now the program can correctly calculate 534 digits of π, until it makes an error.

    3141592653589793238462643383279502884
    1971693993751058209749445923078164062
    8620899862803482534211706798214808651
    3282306647093844609550582231725359408
    1284811174502841027019385211055596446
    2294895493038196442881097566593344612
    8475648233786783165271201909145648566
    9234603486104543266482133936072602491
    4127372458700660631558817488152092096
    2829254091715364367892590360011330530
    5488204665213841469519415116094330572
    7036575959195309218611738193261179310
    5118548074462379962749567351885752724
    8912279381830119491298336733624406566
    43086021394946395
    22421 <-- wrong
    

    16-bit Integer Overflow

    It turns out, during the calculation of the largest terms at the beginning, the error term gets quite large, since the divisors at the beginning are in the range of ~4000. When evaluating the series, numerator actually starts to overflow in the multiplication immediately.

    The integer overflow is insignificant when calculating the first 500 digits, but starts to get worse and worse, until it gives an incorrect result.

    Changing uint16_t numerator = 0 to uint32_t numerator = 0 can solve this problem and calculate π to 1000+ digits.

    However, as I mentioned before, my target platform is a 8-bit CPU, and only has 16-bit operations. Is there a trick to solve the 16-bit integer overflow issue that I'm seeing here, using only one or more uint16_t? If it's not possible to avoid multiple-precision arithmetic, what is the simplest method to implement it here? I know somehow I need to introduce an extra 16-bit "extension word", but I'm not sure how can I implement it.

    And thanks in advance for your patience to understand the long context here.

    解决方案

    Take a look at related QA:

    Its using Wiki: Bailey–Borwein–Plouffe_formula which is more suited for integer arithmetics.

    The real challenge however would be:

    As you probably want to print the number in dec base ...

    Also if you need carry in higher level language than asm take a look at this:

    You can modify it to handle as many carry bits as you need (if still less than the data type bit-width).

    [Edit1] BBP example in C++/VCL

    I used this formula (taken from Wiki page linked above):

    converted to fixed point...

    //---------------------------------------------------------------------------
    AnsiString str_hex2dec(const AnsiString &hex)
        {
        char c;
        AnsiString dec="",s;
        int i,j,l,ll,cy,val;
        int  i0,i1,i2,i3,sig;
        sig=+1; l=hex.Length();
        if (l) { c=hex[l]; if (c=='h') l--; if (c=='H') l--; }
        i0=0; i1=l; i2=0; i3=l;
        for (i=1;i<=l;i++)      // scan for parts of number
            {
            char c=hex[i];
            if (c=='-') sig=-sig;
            if ((c=='.')||(c==',')) i1=i-1;
            if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            if ((c>='A')&&(c<='F')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            if ((c>='a')&&(c<='f')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            }
    
        l=0; s=""; if (i0) for (i=i0;i<=i1;i++)
            {
            c=hex[i];
                 if ((c>='0')&&(c<='9')) c-='0';
            else if ((c>='A')&&(c<='F')) c-='A'-10;
            else if ((c>='a')&&(c<='f')) c-='A'-10;
            for (cy=c,j=1;j<=l;j++)
                {
                val=(s[j]<<4)+cy;
                s[j]=val%10;
                cy  =val/10;
                }
            while (cy>0)
                {
                l++;
                s+=char(cy%10);
                cy/=10;
                }
            }
        if (s!="")
            {
            for (j=1;j<=l;j++) { c=s[j]; if (c<10) c+='0'; else c+='A'-10; s[j]=c; }
            for (i=l,j=1;j<i;j++,i--) { c=s[i]; s[i]=s[j]; s[j]=c; }
            dec+=s;
            }
        if (dec=="") dec="0";
        if (sig<0) dec="-"+dec;
    
        if (i2)
            {
            dec+='.';
            s=hex.SubString(i2,i3-i2+1);
            l=s.Length();
            for (i=1;i<=l;i++)
                {
                c=s[i];
                     if ((c>='0')&&(c<='9')) c-='0';
                else if ((c>='A')&&(c<='F')) c-='A'-10;
                else if ((c>='a')&&(c<='f')) c-='A'-10;
                s[i]=c;
                }
            ll=((l*1234)>>10);  // num of decimals to compute
            for (cy=0,i=1;i<=ll;i++)
                {
                for (cy=0,j=l;j>=1;j--)
                    {
                    val=s[j];
                    val*=10;
                    val+=cy;
                    s[j]=val&15;
                    cy=val>>4;
                    }
                dec+=char(cy+'0');
                for (;;)
                    {
                    if (!l) break;;
                    if (s[l]) break;
                    l--;
                    }
                if (!l) break;;
                }
            }
    
        return dec;
        }
    //---------------------------------------------------------------------------
    AnsiString pi_BBP() // https://en.wikipedia.org/wiki/Bailey–Borwein–Plouffe_formula
        {
        const int N=100;        // 32*N bit uint arithmetics
        int sh;
        AnsiString s;
        uint<N> pi,a,b,k,k2,k3,k4;
    
        for (pi=0,sh=(N<<5)-8,k=0;sh>=0;k++,sh-=4)
            {
            k2=k*k;
            k3=k2*k;
            k4=k3*k;
            a =k2* 120;
            a+=k * 151;
            a+=     47;
            b =k4* 512;
            b+=k3*1024;
            b+=k2* 712;
            b+=k * 194;
            b+=     15;
            a<<=sh;
            pi+=a/b;
            }
        pi<<=4;
        s=pi.strhex();
        s=s.Insert(".",2);
        return str_hex2dec(s);
        }
    //---------------------------------------------------------------------------
    

    The code is using VCL AnsiString which is a self allocating string and mine uint<N> template which is unsigned integer arithmetics of 32*N bitwidth based on mine ALU32. As you can see you only need big integer division addition and multiplication for this (all the other stuff is doable on normal integers).

    Here decadic result versus 1000 digit Pi reference:

    ref: 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989
    BPP: 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778048187
    

    The computed bigint value is exported to hex string and then converted to decadic base using str_hex2dec from link above. The number of iterations depends on the target bitwidth.

    The code is not optimized yet...

    这篇关于通过使用16位算术求序列来计算π时避免溢出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆