首页 > 解决方案 > 使用 64 位分子和分母的 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;

标签: c++cmathpi

解决方案


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

一个样本连分数

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

π的连分数是

[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, ...]

因此我们可以编写一个小 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 位 (!):

3.14159265358979323846264338327950288418 (approximation)
3.14159265358979323846264338327950288419 (actual)

对于您的目标,这应该绰绰有余。(当然,除非你试图设置一个查找 π 或类似数字的记录。^_^)


推荐阅读