C++ 使用64位分子和分母对pi的最佳有理近似是什么?

C++ 使用64位分子和分母对pi的最佳有理近似是什么?,c++,c,math,pi,C++,C,Math,Pi,用两个64位整数表示的Pi最精确的有理对是什么?如果您愿意,可以随意添加其他int类型 这是我的想法,但我相信它会变得更准确,因为分母会变得更大——我只是在考虑10进制。我很确定分子应该是uint64max // c++ inline constexpr auto pi_num = 3141592653589793238ull; inline constexpr auto pi_den = 1000000000000000000ull; // c const unsigned long long

用两个64位整数表示的Pi最精确的有理对是什么?如果您愿意,可以随意添加其他
int
类型

这是我的想法,但我相信它会变得更准确,因为分母会变得更大——我只是在考虑10进制。我很确定分子应该是
uint64
max

// c++
inline constexpr auto pi_num = 3141592653589793238ull;
inline constexpr auto pi_den = 1000000000000000000ull;
// c
const unsigned long long pi_num = 3141592653589793238ull;
const unsigned long long pi_den = 1000000000000000000ull;
您可以使用来获得无理数的最佳近似值。如果您以前没有遇到过连分数,那么这是一种将数字写成形式的嵌套分数系列的方法

在连分数中加入越来越多的项,可以得到一个越来越好的有理数近似值

问题是

因此,我们可以编写一个小Python脚本来计算基于这个连分数表示的近似值,如下所示:

from fractions import *

digits = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1, 1, 15, 3, 13, 1, 4, 2, 6, 6, 99, 1, 2, 2, 6, 3, 5, 1, 1, 6, 8, 1, 7, 1, 2, 3, 7, 1, 2, 1, 1, 12, 1, 1, 1, 3, 1, 1, 8, 1, 1, 2, 1, 6, 1, 1, 5, 2, 2, 3, 1, 2, 4, 4, 16, 1, 161]

for i in range(len(digits)):
    # Start with the last digit
    f = Fraction(digits[i]);

    # Keep rewriting it as term + 1 / prev
    for j in range(i-1, -1, -1):
        f = digits[j] + 1 / f
    
    # Stop if we overshoot
    if f.numerator >= 2**64 or f.denominator >= 2**64: break
    
    # Print the approximation we found
    print(f)
这将以越来越好的近似值打印连续分数,直到我们超出适合64位整数的值。以下是输出:

3
22/7
333/106
355/113
103993/33102
104348/33215
208341/66317
312689/99532
833719/265381
1146408/364913
4272943/1360120
5419351/1725033
80143857/25510582
165707065/52746197
245850922/78256779
411557987/131002976
1068966896/340262731
2549491779/811528438
6167950454/1963319607
14885392687/4738167652
21053343141/6701487259
1783366216531/567663097408
3587785776203/1142027682075
5371151992734/1709690779483
8958937768937/2851718461558
139755218526789/44485467702853
428224593349304/136308121570117
5706674932067741/1816491048114374
6134899525417045/1952799169684491
30246273033735921/9627687726852338
66627445592888887/21208174623389167
430010946591069243/136876735467187340
2646693125139304345/842468587426513207
最后一个近似是π的最佳近似,我相信,它适合64位整数。(可能在这个分母和下一个分母之间会出现一个更好的分母,溢出一个64位整数,但这仍然非常接近!)因此,您希望

const uint64_t pi_num   = 2646693125139304345u;
const uint64_t pi_denom = 842468587426513207u;
报告此近似值精确到小数点后37位(!):


这对于你的目标来说应该足够了。(当然,除非你试图设置一个记录π或类似数字的记录。^ ^ ^)

这个问题与C、C++或甚至编程一般无关。我需要一个精确的
pi
,不想使用浮点数。C++不允许浮点数字作为非类型模板参数,所以我使用了Rational整数,因此更新你的问题以反映整数需求(以及为什么)得到最精确的四元精度表示的PI,可以转储四元组的字节,提取尾数和指数,使用尾数作为分子,2^指数作为分母。切掉位(并降低指数),直到数字适合64位。这将使您获得113位精度(减去删除的精度)。要点是:你希望分母是二的幂,这样在你执行除法运算时就不会发生浮点损失。有趣的是,即使你把数字存储到了那个精度,你在做任何乘法或除法运算的第二秒就会损失很多,除非你得到的结果可以处理两倍的精度大小(这里是256位)。注意使用128位(两个64位整数)和log10(2^128)≈ 38.5,所以37位小数(加上初始数字)与我们预期的差不多。如果不使用生成高精度小数表示的库显式测试范围内的所有剩余数字,我不确定是否有一种简单的方法可以测试其余分母,以确定它们中的任何一个是否能给出更好的近似值。对不起!正如所描述的,最好的算法比截断连续的分数稍微复杂一些。@ ANATOLYG:真的,除了收敛之外,还需要考虑半字节。在这种特殊情况下,有六个分子严格介于
264669125139304345
2^64
之间的半聚合体;这些半收敛是π的最佳可能上界,但不是最佳可能上界,因此,
264669125139304345/842468587466513207
确实是π的最佳可能近似,分子和分母均以
2^64
为界。54,有此数据(我用绝对误差注释):
496638392183958130/1580848410090576507(3.75e-35);926649338775027373/294961645557763847(1.61e-35);1356660285366096616/4318381024951187(8.26e-36);1786671231957165859/568715116492138527(4.19e-36);2216682178548235102/705591851959325867(1.70e-36);264669125139304345/842468587426513207(1.41e-38);5723397196869677933/1821813910320213754(6.37e-37)
。最后一对数字似乎是错误的。
const uint64_t pi_num   = 2646693125139304345u;
const uint64_t pi_denom = 842468587426513207u;
3.14159265358979323846264338327950288418 (approximation)
3.14159265358979323846264338327950288419 (actual)