我在这里使用符号
可以通过计算然后应用定义来找到数字的连续分数,但这需要至少O(n)位的内存来找到 0 , 1 ... a n ,实际上情况要糟糕得多。使用双浮点精度,只能找到 0 , 1 ... a 19 。
另一种方法是使用以下事实:如果a,b,c是有理数,则存在唯一有理数p,q,r,使得1 /(a + b * 2 1/3 + c * 2 2/3 )= x + y * 2 1/3 + z * 2 2/3 ,即
因此,如果我使用boost rational lib将x,y和z表示为绝对精度,我可以获得floor(x + y * 2 1/3 + z * 2 2 / 3 )准确地仅对2 1/3 和2 2/3 使用双精度,因为我只需要它在真值的1/2之内。不幸的是,x,y和z的分子和分母增长得相当快,如果你使用常规浮点数而错误堆积很快。
这样我就可以在一小时内计算出一个 0 ,一个 1 ...一个 10000 ,但不知何故mathematica可以在2秒内完成。这是我的参考代码
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
namespace mp = boost::multiprecision;
int main()
{
const double t_1 = 1.259921049894873164767210607278228350570251;
const double t_2 = 1.587401051968199474751705639272308260391493;
mp::cpp_rational p = 0;
mp::cpp_rational q = 1;
mp::cpp_rational r = 0;
for(unsigned int i = 1; i != 10001; ++i) {
double p_f = static_cast<double>(p);
double q_f = static_cast<double>(q);
double r_f = static_cast<double>(r);
uint64_t floor = p_f + t_1 * q_f + t_2 * r_f;
std::cout << floor << ", ";
p -= floor;
//std::cout << floor << " " << p << " " << q << " " << r << std::endl;
mp::cpp_rational den = (p * p * p + 2 * q * q * q +
4 * r * r * r - 6 * p * q * r);
mp::cpp_rational a = (p * p - 2 * q * r) / den;
mp::cpp_rational b = (2 * r * r - p * q) / den;
mp::cpp_rational c = (q * q - p * r) / den;
p = a;
q = b;
r = c;
}
return 0;
}
答案 0 :(得分:2)
拉格朗日算法
该算法在例如Knuth的书“计算机程序设计的艺术”第2卷(第4.5节“欧几里德算法分析中的第13章,第3版第375页”)中进行了描述。 / p>
设f
为整数系数的多项式,其唯一实根是无理数x0 > 1
。然后拉格朗日算法计算x0
的连续分数的连续商。
我在python中实现了它
def cf(a, N=10):
"""
a : list - coefficients of the polynomial,
i.e. f(x) = a[0] + a[1]*x + ... + a[n]*x^n
N : number of quotients to output
"""
# Degree of the polynomial
n = len(a) - 1
# List of consecutive quotients
ans = []
def shift_poly():
"""
Replaces plynomial f(x) with f(x+1) (shifts its graph to the left).
"""
for k in range(n):
for j in range(n - 1, k - 1, -1):
a[j] += a[j+1]
for _ in range(N):
quotient = 1
shift_poly()
# While the root is >1 shift it left
while sum(a) < 0:
quotient += 1
shift_poly()
# Otherwise, we have the next quotient
ans.append(quotient)
# Replace polynomial f(x) with -x^n * f(1/x)
a.reverse()
a = [-x for x in a]
return ans
我的计算机上运行cf([-2, 0, 0, 1], 10000)
大约需要1秒。 (系数对应于多项式x^3 - 2
,其唯一实根为2 ^(1/3)。)输出与Wolfram Alpha中的输出一致。
<强>买者强>
在函数内部计算的多项式的系数很快变为非常大的整数。所以这种方法需要在其他语言中实现一些bigint(纯python3处理它,但是例如numpy不会。)
答案 1 :(得分:1)
你可能有更多的运气计算2 ^(1/3)到高精度,然后尝试从中导出连续分数,使用区间运算来确定精度是否足够。
这是我在Python中使用Halley迭代来计算固定点的2 ^(1/3)。死代码试图通过牛顿迭代比Python更有效地计算定点倒数 - 没有骰子。
从我的机器开始的时间大约是30秒,主要用于从固定点表示中提取连续分数。
prec = 40000
a = 1 << (3 * prec + 1)
two_a = a << 1
x = 5 << (prec - 2)
while True:
x_cubed = x * x * x
two_x_cubed = x_cubed << 1
x_prime = x * (x_cubed + two_a) // (two_x_cubed + a)
if -1 <= x_prime - x <= 1: break
x = x_prime
cf = []
four_to_the_prec = 1 << (2 * prec)
for i in range(10000):
q = x >> prec
r = x - (q << prec)
cf.append(q)
if True:
x = four_to_the_prec // r
else:
x = 1 << (2 * prec - r.bit_length())
while True:
delta_x = (x * ((four_to_the_prec - r * x) >> prec)) >> prec
if not delta_x: break
x += delta_x
print(cf)