我目前正在编写计算器应用程序。我正试图在其中编写衍生估算器。下面的公式是一种简单的方法。通常在纸上你会使用最小的h来获得最准确的估计。问题是双打无法处理将相当大的数字添加到真正的小数字。例如4 + 1E-200只会产生4.0。即使h只是1E-16,4 + 1E16实际上会给你正确的值,但是数学它是不准确的,因为在第16位之后的任何东西都会丢失并且舍入不能正确发生。我听说双打的一般经验法则是1E-8或1E-7。这个问题是大数字不会工作,因为2E231 + 1E-8只是2E23,1E-8将因为尺寸问题而丢失。
f'(x)=(f(x+h)-f(x))/h as x approaches 0
当我在第4点测试f(x)= x ^ 2所以f'(4)时,它应该是8
现在我明白我可能永远不会得到8.但我最准确的似乎是1E-7或1E8左右
有趣的是1E-9所有1E-11给出了相同的答案。
以下是f(x)=x^2 at x=4
1E-7 8.000000129015916
1E-8 7.999999951380232
1E-9 8.000000661922968
1E-10 8.000000661922968
1E-11 8.000000661922968
1E-12 8.000711204658728
以下是我的问题:
ANSWERED
非常感谢BobG。该应用程序目前计划为2种形式,即命令行PC应用程序。还有一个Android应用程序。特别要感谢About页面的部分内容。如果你想它将是开源的,但我没有发布到项目网站的链接,直到我找出一些非常大的错误。目前我一直称它为Mathulator,但名称可能会改变,因为它已经有版权并且听起来很愚蠢。我不知道发布候选版本何时会运行,目前我还没有任何线索会稳定的。但如果我能实现我想要的一切,它将会非常强大。再次感谢。快乐编程。
答案 0 :(得分:3)
有一本书可以回答这个问题(和其他人一样):
数字食谱在C ,第2版,由Press,Vetterling,Teukolsky和Flannery。本书还有C ++,Fortran和BASIC版本。可悲的是,没有Java版本。此外,我相信这本书绝版,但可以在线购买某些口味的二手版本(至少通过bn.com。)
第5.7节“数值导数”,p。 186准确地解释了你在数值导数和数字导数背后的数学问题,以及如何正确计算数值导数的函数(在C中,但它应该很容易转换为Java)。它们的简单近似概述如下:
1)在数值上,你最好不要计算对称版本:
f'(x)=(f(x + h) - f(x - h))/ 2h
2)h应该是近似的(sigma_f)^(1/3)* x_c
,其中
sigma_f =〜对于简单函数计算f(x)的分数精度
x_c = ~x,除非x等于零。
然而,这不会产生最佳导数,因为误差是〜(sigma_f)^(2/3)。一个更好的解决方案是Ridders算法,该书在本书中作为C程序呈现(参考Ridders,C.J.F。1982,Advances in Engineering Software,第4卷,第2期,第75-76页。)
答案 1 :(得分:2)
阅读题为“每位程序员应该了解浮点数”的论文(google for it)。然后,您将看到大多数浮动值大致表示在计算机硬件中。
要进行没有此缺点的计算,请使用符号计算。但这并不像使用浮点那样有效。
要使浮点结果保持一致,请使用舍入到最接近的幂10,例如0.1,0.01等。要了解何时应停止近似,请在近似步骤中使用某种阈值进行监视。例如,如果执行下一个近似步骤仅产生.001%的变化已经计算出的值,那么继续近似是没有意义的。
更新很久以前我有我的数值计算类,但我可以模糊地回忆起减去接近的数字是非常糟糕的,因为如果数字非常接近,那么最可靠的数字会被取消,你就不可靠了数字。这正是减少h
时发生的情况。在这些情况下建议的是替代减法与其他一些操作。例如,您可以切换到`f(x)展开的某种系列。
我不太明白你的第二个问题,因为答案取决于你的要求 - “尽可能多的”。
顺便说一下,在math.stackexchange.com上找到问题的答案可能会更好。
此外,请访问thrashgod
提供的链接:Numerical differentiation
答案 2 :(得分:2)
1.浮点数(浮点数和双精度数)的精度取决于数字的绝对值。双打精度约为15位,因此您可以添加1 + 1e-15
,但10 + 1e-15
可能会再次为10,因此您必须执行10 + 1e-14
。为了获得有意义的结果,我建议你将1e-8乘以原始数字的绝对值,这将在导数中给出大约7个正确的数字。类似的东西:
double h = x * 1e-8;
double derivative = (f(x+h) - f(x)) / h;
无论如何,这是一个近似值,比方说,如果你试图在x = 1e9处计算sin(x)的导数,你将得到h = 10并且结果都是错误的。但对于“有趣”部分接近零的“常规”功能,这将很有效。
2.少于“h”,您对衍生物进行采样的点越精确,但您得到的导数的正确数字越少。我无法证明这一点,但我的直觉是h = x * 1e-8
7 = 15 - 8
得到double
正确的数字,其中15是double derivative = (f(x+h) - f(x-h)) / (2*h);
的精确度。
此外,使用“更对称”公式是个好主意,它给出了二阶多项式的绝对正确答案:
{{1}}
答案 3 :(得分:1)
我的问题是什么是最合适的 h ,以及它如何缩放到任何大小。
如Numerical Differentiation所述, h 的合适选择是 sqrt(ɛ) * x ,其中 ɛ是machine epsilon。
答案 4 :(得分:0)
我会使用BigDecimal类进行这种计算,虽然它不是你问题的答案,但它确实会提高浮点运算的精度。
答案 5 :(得分:0)
根据Javadoc,11位代表指数,52位代表有效数字。忽略指数,似乎你有52位可以使用。所以如果你选择h = x * 2 ^ -40,你在这里使用了40位,你将看到的精度是2 ^ -12。根据您的需要调整此比率。