使用 64 位分子和分母对 pi 的最佳有理近似值是多少?

14 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 pi_num = 3141592653589793238ull;
const unsigned long long pi_den = 1000000000000000000ull;
Run Code Online (Sandbox Code Playgroud)

tem*_*def 24

您可以使用连分数来获得无理数的极好近似值。如果您以前没有遇到过连分数,这是一种将数字写成以下形式的嵌套分数系列的方法

样本连分数

将越来越多的项添加到连分数中可以得到越来越好的有理数近似值。

的连分数 ?

[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, ...]
Run Code Online (Sandbox Code Playgroud)

因此我们可以编写一个小的 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)
Run Code Online (Sandbox Code Playgroud)

这会以越来越好的近似值打印连分数,直到我们超过适合 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
Run Code Online (Sandbox Code Playgroud)

最后一个近似值是 ? 的最佳近似值,我相信它适合 64 位整数。(有可能在这个分母和下一个分母之间出现一个更好的分母,你会得到一个 64 位整数溢出,但这仍然非常接近!)因此,你想要

const uint64_t pi_num   = 2646693125139304345u;
const uint64_t pi_denom = 842468587426513207u;
Run Code Online (Sandbox Code Playgroud)

这个来源报告说这个近似值精确到小数点后 37 位 (!):

3.14159265358979323846264338327950288418 (approximation)
3.14159265358979323846264338327950288419 (actual)
Run Code Online (Sandbox Code Playgroud)

这应该足以满足您的目标。(当然,除非您尝试设置查找 ? 或类似数字的记录。^_^)

  • 请注意,使用了 128 位(两个 64 位整数),并且 log10(2^128) ≈ 38.5,因此 37 位小数(加上初始数字)大约是我们所期望的。 (6认同)
  • 正如[维基百科文章](https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations)中所述,最好的算法比仅仅截断连分数稍微复杂一些。 (3认同)
  • 约翰尼斯·沃利斯 (Johannis Wallis),《代数论;历史与实践》,牛津 1685 年,第 14 页。54、有这个数据(我用绝对错误注释):`496638392183958130 / 158084910090576507 (3.75e-35); 926649338775027373 / 294961645557763847 (1.61e-35); 1356660285366096616 / 431838381024951187 (8.26e-36); 1786671231957165859 / 568715116492138527 (4.19e-36); 2216682178548235102 / 705591851959325867 (1.70e-36); 2646693125139304345 / 842468587426513207 (1.41e-38); 5723397196869677933 / 1821813910320213754 (6.37e-37)`。最后一对数字似乎是错误的。 (3认同)
  • @anatolyg:正确 - 除了收敛性之外,还需要考虑半收敛性。在这种特殊情况下,有六个半收敛分子严格位于“2646693125139304345”和“2^64”之间;这些半收敛是 π 的最佳可能上界,但不是最佳可能的边界,因此“2646693125139304345/842468587426513207”确实是分子和分母都以“2^64”为界的 π 的最佳可能近似值。 (2认同)