Java估计某个点的导数

我目前正在写一个计算器应用程序。我正试图在其中编写衍生估算器。下面的公式是一种简单的方法。通常在纸上你会使用最小的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
这是我的问题: 选择h的最佳方法是什么,显然1E-8或1E-7有意义,但我怎样才能选择基于x的h,这样即使x为3.14E203或2E-231也可以使用任何大小的数字。 我应该考虑多少小数的精度。 你知道德州仪器是如何做到的,TI 83,84和Inspire可以数字地计算出12位小数或精度的衍生物,几乎总是正确的,但无论如何它们的最大精度是12位数,那些计算器是非CAS,所以他们实际上并没有得到任何东西 逻辑上有一个介于1E-7和1E-8之间的数字会给我一个更精确的结果,有没有办法找到这个数字,或者至少接近它。 ANSWERED 非常感谢BobG。该应用程序目前计划为2种形式,即命令行PC应用程序。还有一个Android应用程序。特别要感谢About页面的部分内容。如果你想它将是开源的,但我没有发布到项目网站的链接,直到我找出一些非常大的错误。目前我一直称它为Mathulator,但名称可能会改变,因为它已经有版权并且听起来很愚蠢。我不知道发布候选版本何时会运行,目前我还没有任何线索会稳定的。但如果我能实现我想要的一切,它将会非常强大。再次感谢。快乐的编程。     
已邀请:
有一本书可以回答这个问题(和其他人一样): 数字食谱在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,vol.4,no.2,pp 75-76。)     
阅读题为“每位程序员应该了解浮点数”的论文(google for it)。然后,您将看到大多数浮动值大致表示在计算机硬件中。 要进行没有此缺点的计算,请使用符号计算。但这不如使用浮点效率高。 要使浮点结果保持一致,请使用舍入到最接近10的幂,例如0.1,0.01等。要了解何时应停止近似,请在近似步骤中使用某种阈值进行监视。例如,如果执行下一个近似步骤仅产生.001%的变化已经计算出的值,那么继续近似是没有意义的。 更新我很久以前就有了我的数值计算类,但我可以模糊地回想起减去接近的数字是非常糟糕的,因为如果数字非常接近,那么最可靠的数字会被取消,你的数字就不可靠。这正是你减少
h
时会发生的事情。在这些情况下建议的是替代减法与其他一些操作。例如,您可以切换到`f(x)展开的某种系列。 我不太明白你的第二个问题,因为答案取决于你的要求 - “你想要多少”。 顺便说一下,您可以在math.stackexchange.com上找到问题的答案。 另外,访问
thrashgod
提供的链接:数字微分     
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
正确的数字,其中15是
double
的精度。 此外,使用“更对称”公式是一个好主意,它给出了二阶多项式的绝对正确答案:
double derivative = (f(x+h) - f(x-h)) / (2*h);
    
  我的问题是什么是最合适的h,它如何缩放到任何大小。 如数值微分中所述,h的合适选择是sqrt(ɛ)* x,其中ɛ是机器epsilon。     
我会使用BigDecimal类进行这种计算,虽然它不是你问题的答案,但它确实会提高浮点运算的精度。     
根据Javadoc,11位代表指数,52位代表有效数字。忽略指数,似乎你有52位可以使用。所以如果你选择h = x * 2 ^ -40,你在这里使用了40位,你将看到的精度是2 ^ -12。根据您的需要调整此比率。     

要回复问题请先登录注册