繁体   English   中英

Java估计一个点的导数

[英]Java estimate a derivative at a point

我目前正在编写一个计算器应用程序。 我试图在其中写一个导数估计器。 下面的公式是一种简单的方法。 通常,在纸上,您将使用尽可能小的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'(4)上测试f(x)= x ^ 2时,它应该恰好是8,现在我知道我可能永远也不会精确得到8。但是我最准确的似乎是1E- 7或1E8有趣的是1E-9到1E-11都给出相同的答案。 这是h的列表,以及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

这是我的问题:

  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之间会有一个数字,它将为我提供更精确的结果,是否可以找到该数字,或者至少可以接近该数字。

回答

非常感谢BobG。 目前,该应用程序计划采用两种形式,即命令行PC应用程序。 还有一个Android应用程序。 特别感谢您的“关于”页面部分。 如果您希望它是开源的,但是在我解决一些非常大的错误之前,我不会发布指向项目站点的链接。 目前我一直称其为Mathulator,但名称可能会更改,因为它已经拥有版权并且听起来很愚蠢。我不知道何时发布候选版本将要运行,目前我不知道何时发布会稳定的。 但是如果我也能实现我想要的一切,它将非常强大。再次感谢。 编程愉快。

有一本书可以回答这个问题(和其他类似的问题):

C ,第二版的数字食谱 ,出版社,Vetterling,Teukolsky和Flannery。 本书还提供C ++,Fortran和BASIC版本。 可悲的是,不存在Java版本。 此外,我认为这本书已经绝版,但可以在线购买某些口味的二手版本(至少通过bn.com)。

第5.7节“数值导数”,第2页。 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,CJF 1982,Advances in Engineering Software,第4卷,第2期,第75-76页)。

阅读标题为“每个程序员应了解的浮点知识”的论文(为此,请使用Google)。 然后,您将看到大多数浮点值大约在计算机硬件中表示。

要进行计算而没有此缺点,请使用符号计算。 但这不如使用浮点数有效。

要使浮点结果一致,请使用四舍五入到最接近的10的幂,例如0.1、0.01等。要了解何时应停止逼近,请在近似步骤中使用某种阈值来注意。 例如,如果执行下一个逼近步骤,仅对已计算的值产生0.001%的变化,则没有理由继续逼近。

更新我很早以前就有数值计算课程,但是我可以隐约地记得减去接近数非常不好,因为如果数字非常接近,最可靠的数字就会被抵消,而您的数字也不可靠。 当您减小h时,这正是发生的情况。 在这些情况下,建议将减法替换为其他一些操作。 例如,您可以切换到f(x)扩展到的某种系列。

我不太了解您的第二个问题,因为答案取决于您的要求-“您所希望的数量”。

顺便说一句,如果您在math.stackexchange.com上找到问题的答案,可能会比较幸运。

此外,访问thrashgod提供的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 h = x * 1e-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。 根据您的需要调整此比例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM