Java估计了某一点的导数

时间:2011-04-04 20:11:37

标签: java math calculator calculus derivative

我目前正在编写计算器应用程序。我正试图在其中编写衍生估算器。下面的公式是一种简单的方法。通常在纸上你会使用最小的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

的h和结果列表
1E-7 8.000000129015916
1E-8 7.999999951380232
1E-9 8.000000661922968
1E-10 8.000000661922968
1E-11 8.000000661922968
1E-12 8.000711204658728

以下是我的问题:

  1. 选择h的最佳方式是什么,显然1E-8或1E-7有意义,但我怎样才能选择基于x的h,这样即使x为3.14E203,它也适用于任何大小的数字2E-231。
  2. 我应该考虑多少小数的精度。
  3. 你知道德州乐器如何做到这一点,TI 83,84和Inspire可以数字地计算衍生物到12位小数或精度,几乎总是正确的,但无论如何它们的最大精度是12位数那些计算器是非CAS的,所以他们实际上并没有得到任何东西
  4. 从逻辑上讲,1E-7和1E-8之间有一个数字会给我一个更精确的结果,有没有办法找到这个数字,或者至少接近它。
  5. ANSWERED

    非常感谢BobG。该应用程序目前计划为2种形式,即命令行PC应用程序。还有一个Android应用程序。特别要感谢About页面的部分内容。如果你想它将是开源的,但我没有发布到项目网站的链接,直到我找出一些非常大的错误。目前我一直称它为Mathulator,但名称可能会改变,因为它已经有版权并且听起来很愚蠢。我不知道发布候选版本何时会运行,目前我还没有任何线索会稳定的。但如果我能实现我想要的一切,它将会非常强大。再次感谢。快乐编程。

6 个答案:

答案 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。根据您的需要调整此比率。