我发现了我自己的算法来计算从 Faulhaber 公式获得的多项式的系数;它、它的证明和几个实现可以在github.com/fcard/PolySum 找到。这个问题启发我加入了一个 c++ 实现(使用 GMP 库来获取任意精度数),在撰写本文时减去几个可用性特性,它是:
#include <gmpxx.h>
#include <vector>
namespace polysum {
typedef std::vector<mpq_class> mpq_row;
typedef std::vector<mpq_class> mpq_column;
typedef std::vector<mpq_row> mpq_matrix;
mpq_matrix make_matrix(size_t n) {
mpq_matrix A(n+1, mpq_row(n+2, 0));
A[0] = mpq_row(n+2, 1);
for (size_t i = 1; i < n+1; i++) {
for (size_t j = i; j < n+1; j++) {
A[i][j] += A[i-1][j];
A[i][j] *= (j - i + 2);
}
A[i][n+1] = A[i][n-1];
}
A[n][n+1] = A[n-1][n+1];
return A;
}
void reduced_row_echelon(mpq_matrix& A) {
size_t n = A.size() - 1;
for (size_t i = n; i+1 > 0; i--) {
A[i][n+1] /= A[i][i];
A[i][i] = 1;
for (size_t j = i-1; j+1 > 0; j--) {
auto p = A[j][i];
A[j][i] = 0;
A[j][n+1] -= A[i][n+1] * p;
}
}
}
mpq_column sum_coefficients(size_t n) {
auto A = make_matrix(n);
reduced_row_echelon(A);
mpq_column result;
for (auto row: A) {
result.push_back(row[n+1]);
}
return result;
}
}
我们可以像这样使用上面的:
#include <cmath>
#include <gmpxx.h>
#include <polysum.h>
mpq_class power_sum(size_t K, unsigned int N) {
auto coeffs = polysum::sum_coefficients(K)
mpq_class result(0);
for (size_t i = 0; i <= K; i++) {
result += A[i][n+1] * pow(N, i+1);
}
return result;
}
完整的实现提供了一个可打印和可调用的Polynomial 类,以及一个polysum 函数来构造一个作为另一个多项式的和。
#include "polysum.h"
void power_sum_print(size_t K, unsigned int N) {
auto F = polysum::polysum(K);
std::cout << "polynomial: " << F;
std::cout << "result: " << F(N);
}
至于效率,上面在我的计算机上计算K=1000 和N=1e16 的结果大约在1.75 秒内,而更成熟和优化的SymPy 实现在同一时间大约需要90 秒机器和mathematica,需要30 秒。对于K=3000,上面大约需要4 分钟,mathematica 几乎花了20 分钟,(但使用的内存要少得多),我让 sympy 整夜运行但它没有完成,可能是因为它内存不足.
可以在此处进行的优化包括使矩阵稀疏并利用仅需要计算一半行和列的事实。链接仓库中的 Rust 版本实现了稀疏和行优化,大约需要 0.7 秒来计算 K=1000,大约 45 来计算 K=3000(分别使用内存的 105mb 和 2.9gb) . Haskell 版本实现了所有三个优化,对于 K=1000 大约需要 1 秒,对于 K=3000 大约需要 34 秒。 (分别使用内存的60mb 和880mb)和完全未优化的python 实现对于K=1000 大约需要12 秒,但对于K=3000 内存不足。
无论使用何种语言,这种方法似乎都是最快的,但研究仍在进行中。由于舒尔茨的方法也归结为求解n+1 方程组,并且应该能够以相同的方式进行优化,这将取决于他的矩阵计算速度是否更快。此外,内存使用量根本无法很好地扩展,Mathematica 仍然是这里的明显赢家,仅使用 80mb 代替 K=3000。我们拭目以待。