【发布时间】:2020-08-18 17:07:26
【问题描述】:
有谁知道如何用 Python 编写一个计算调和级数相加的程序。即 1 + 1/2 +1/3 +1/4...
【问题讨论】:
-
调和级数的第一项是1
有谁知道如何用 Python 编写一个计算调和级数相加的程序。即 1 + 1/2 +1/3 +1/4...
【问题讨论】:
@Kiv's answer 是正确的,但如果您不需要无限精度,那么对于大 n 来说它会很慢。在这种情况下最好使用asymptotic formula:
#!/usr/bin/env python
from math import log
def H(n):
"""Returns an approximate value of n-th harmonic number.
http://en.wikipedia.org/wiki/Harmonic_number
"""
# Euler-Mascheroni constant
gamma = 0.57721566490153286060651209008240243104215933593992
return gamma + log(n) + 0.5/n - 1./(12*n**2) + 1./(120*n**4)
@Kiv's answer 用于 Python 2.6:
from fractions import Fraction
harmonic_number = lambda n: sum(Fraction(1, d) for d in xrange(1, n+1))
例子:
>>> N = 100
>>> h_exact = harmonic_number(N)
>>> h = H(N)
>>> rel_err = (abs(h - h_exact) / h_exact)
>>> print n, "%r" % h, "%.2g" % rel_err
100 5.1873775176396242 6.8e-16
N = 100 处的相对误差小于1e-15。
【讨论】:
@recursive's solution 对于浮点近似是正确的。如果您愿意,您可以使用分数模块在 Python 3.0 中获得确切答案:
>>> from fractions import Fraction
>>> def calc_harmonic(n):
... return sum(Fraction(1, d) for d in range(1, n + 1))
...
>>> calc_harmonic(20) # sum of the first 20 terms
Fraction(55835135, 15519504)
请注意,位数增长很快,因此对于较大的 n,这将需要大量内存。如果您想要真正花哨的话,您还可以使用生成器来查看一系列部分和。
【讨论】:
range(1, n) 生成 (n-1) 项目而不是 n 项目所需。前 20 个术语的总和是 55835135/ 15519504。见stackoverflow.com/questions/404346/…
range 不仅重命名为xrange,例如,range 接受大整数但xrange 不接受。
只是对使用浮点的其他答案的脚注;从最大的除数开始并向下迭代(朝着具有最大值的倒数)将尽可能推迟累积的舍入误差。
【讨论】:
可以使用 digamma 函数计算 H 函数的快速、准确、平滑、复值版本,如 here 所述。 Euler-Mascheroni (gamma) 常数和 digamma 函数分别在 numpy 和 scipy 库中提供。
from numpy import euler_gamma
from scipy.special import digamma
def digamma_H(s):
""" If s is complex the result becomes complex. """
return digamma(s + 1) + euler_gamma
from fractions import Fraction
def Kiv_H(n):
return sum(Fraction(1, d) for d in xrange(1, n + 1))
def J_F_Sebastian_H(n):
return euler_gamma + log(n) + 0.5/n - 1./(12*n**2) + 1./(120*n**4)
下面是三种方法的速度和精度对比(以Kiv_H为参考):
Kiv_H(x) J_F_Sebastian_H(x) digamma_H(x)
x seconds bits seconds bits seconds bits
1 5.06e-05 exact 2.47e-06 8.8 1.16e-05 exact
10 4.45e-04 exact 3.25e-06 29.5 1.17e-05 52.6
100 7.64e-03 exact 3.65e-06 50.4 1.17e-05 exact
1000 7.62e-01 exact 5.92e-06 52.9 1.19e-05 exact
【讨论】:
调和级数发散,即其和为无穷大..
编辑:除非你想要部分总和,但你并不太清楚。
【讨论】:
这应该可以解决问题。
def calc_harmonic(n):
return sum(1.0/d for d in range(2,n+1))
【讨论】:
np.sum,它将进行成对求和。
这个怎么样:
partialsum = 0
for i in xrange(1,1000000):
partialsum += 1.0 / i
print partialsum
其中 1000000 是上限。
【讨论】:
家庭作业?
这是一个发散级数,因此不可能对所有项进行总结。
我不懂 Python,但我知道如何用 Java 编写它。
public class Harmonic
{
private static final int DEFAULT_NUM_TERMS = 10;
public static void main(String[] args)
{
int numTerms = ((args.length > 0) ? Integer.parseInt(args[0]) : DEFAULT_NUM_TERMS);
System.out.println("sum of " + numTerms + " terms=" + sum(numTerms));
}
public static double sum(int numTerms)
{
double sum = 0.0;
if (numTerms > 0)
{
for (int k = 1; k <= numTerms; ++k)
{
sum += 1.0/k;
}
}
return sum;
}
}
【讨论】:
使用简单的 for 循环
def harmonicNumber(n):
x=0
for i in range (0,n):
x=x+ 1/(i+1)
return x
【讨论】:
我添加了另一个解决方案,这次使用递归来找到第 n 个谐波数。
函数原型: harmonic_recursive(n)
函数参数: n - 第n次谐波数
基本情况:如果n 等于1,则返回1。
重复步骤: 如果不是基本情况,请调用 harmonic_recursive 获取 n-1 术语并将结果与 1/n 添加。这样,我们每次将谐波级数的第 i 项与之前所有项的总和相加。
(这个解决方案也可以很容易地用其他语言实现。)
harmonic_recursive(n):
if n == 1:
return 1
else:
return 1/n + harmonic_recursive(n-1)
def harmonic_recursive(n):
if n == 1:
return 1
else:
return 1.0/n + harmonic_recursive(n-1)
【讨论】:
timeit,在 Python 3.6.1 中使用了一个等效的迭代函数 n=1000,你的代码得到了 420 µs,迭代函数得到了 140 µs。一般的函数调用和特别是 Python 中的递归调用是昂贵的。我确实在 Python 中使用了递归,但在迭代同样清晰时却没有。当然,这里的时间差绝对值很小,所以除非 n 很大,否则这是无稽之谈。
通过使用numpy 模块,您也可以选择使用:
import numpy as np
def HN(n):
return sum(1/arange(1,n+1))
【讨论】: