我需要评估一行的总和:1/1+1/2+1/3+...+1/n。考虑到在C ++中,评估不是完全准确的,求和的顺序非常重要。表达式1/n+1/(n-1)+...+1/2+1/1可以提供更准确的结果。因此,我需要找出提供最大精度的求和顺序。我甚至不知道从哪里开始。实现的首选语言是C++。如果有任何错误,对不起。
我需要评估一行的总和:1/1+1/2+1/3+...+1/n。考虑到在C ++中,评估不是完全准确的,求和的顺序非常重要。表达式1/n+1/(n-1)+...+1/2+1/1可以提供更准确的结果。因此,我需要找出提供最大精度的求和顺序。我甚至不知道从哪里开始。实现的首选语言是C++。如果有任何错误,对不起。
对于较大的n值,最好使用渐进公式,例如 http://en.wikipedia.org/wiki/Harmonic_number 上的公式;
另一种方法是使用exp-log转换。 基本上:
H_n = 1 + 1/2 + 1/3 + ... + 1/n = log(exp(1 + 1/2 + 1/3 + ... + 1/n)) = log(exp(1) * exp(1/2) * exp(1/3) * ... * exp(1/n)).
通过标准库,可以相当快速和准确地计算指数和对数。使用乘法可以获得更准确的结果。
如果这是你的作业并且需要使用简单的加法,你最好按其他人建议从小到大逐个相加。
我甚至不知道从哪里开始。
除非您使用一些准确的闭式表示,否则小到大的有序求和很可能是最准确的简单解决方案(我不清楚为什么对数指数会有帮助-那是一个巧妙的技巧,但据我所知,在这里你没有赢得任何东西)。
您可以通过意识到在一段时间后,总和将变得“量化”来进一步提高精度:实际上,当您具有2位数字精度时,将1.3加到41中的结果为42,而不是42.3-但通过保持“误差”项,您几乎可以将精度翻倍。这称为Kahan Summation。您将计算误差项(42-41-1.3 == -0.3),并通过在下一次添加之前将0.3添加到下一个术语中来进行更正。
在小到大排序中使用Kahan求和法,可能是你需要的最准确的方法。我真的怀疑你会需要更好的方法来处理谐波级数 - 毕竟,即使进行2^45次迭代(非常多),你仍然只需要处理至少为1/2^45的数字,并且总和大约为45(<2^6),因此差异为51个二进制位 - 即使添加“错误”的顺序,仍然可以用双精度变量表示。
如果你按照从小到大的顺序,并使用Kahan求和法,今天的处理器在达到百分之一的误差之前,太阳可能已经熄灭了 - 而且由于该规模上的单个项误差,你将首先遇到其他棘手的精度问题(因为2^53或更大的数字根本无法准确地表示为双精度)。
我不确定求和的顺序是否很重要,以前没有听说过。我猜你想在浮点运算中进行这个操作,所以首先要考虑更多类似于(1.0/1.0 + 1.0/2.0+1.0/3.0)的方式 - 否则编译器会执行整数除法。
要确定评估的顺序,也许可以使用for循环或括号?
例如:
float f = 0.0;
for (int i=n; i>0; --i)
{
f += 1.0/static_cast<float>(i);
}
哦,我忘了说,编译器通常有开关来确定浮点计算模式。这可能与您在求和顺序上所说的相关 - 在 Visual C + 中,它们可以在代码生成编译设置中找到,在 g++ 中则有处理此类情况的选项 -float。
实际上,其他人是正确的 - 您应该按最小分量的顺序进行求和;因此 1 / n + 1 / (n-1) .. 1/1
这是因为浮点数的精度与比例有关,如果从1开始,则相对于1.0,您将获得23位的精度。如果从较小的数字开始,精度会相对于较小的数字,因此您将获得相对于1xe-200或其他数字的23位精度。然后随着数字变大,将出现舍入误差,但总体误差将小于另一个方向。
(defun sum_harmonic (n acc)
(if (= n 0) acc (sum_harmonic (- n 1) (+ acc (/ 1 n)))))
(sum_harmonic 10 0)
7381/2520
[2.9289682]
(sum_harmonic 100 0)
14466636279520351160221518043104131447711/278881500918849908658135235741249214272
[5.1873775]
(sum_harmonic 1000 0)
53362913282294785045591045624042980409652472280384260097101349248456268889497101
75750609790198503569140908873155046809837844217211788500946430234432656602250210
02784256328520814055449412104425101426727702947747127089179639677796104532246924
26866468888281582071984897105110796873249319155529397017508931564519976085734473
01418328401172441228064907430770373668317005580029365923508858936023528585280816
0759574737836655413175508131522517/712886527466509305316638415571427292066835886
18858930404520019911543240875811114994764441519138715869117178170195752565129802
64067621009251465871004305131072686268143200196609974862745937188343705015434452
52373974529896314567498212823695623282379401106880926231770886197954079124775455
80493264757378299233527517967352480424636380511370343312147817468508784534856780
21888075373249921995672056932029099390891687487672697950931603520000
[7.485471]
因此,下一个更好的选择可能是维护浮点数列表,并在每个步骤中将两个最小的数字相加以减少它...