2011-04-04 51 views
1

我目前正在编写一个计算器应用程序。我正在试图写一个派生估计器。下面的公式是一个简单的方法。通常在纸上,您可以使用最小的h来获得最准确的估计值。问题是双打无法处理增加真正的小数字到相对庞大的数字。如4 + 1E-200只会导致4.0。即使h只是1E-16,4 + 1E16实际上会给你正确的价值,但是做数学它是不准确的,因为在第16名之后的任何东西都会丢失,舍入不能正确发生。我听说双打的一般经验法则是1E-8或1E-7。与此问题是大数不会工作,因为2E231 + 1E-8将只是2E23,1E-8将因为尺寸问题而丢失。Java在某个点估算衍生物

f'(x)=(f(x+h)-f(x))/h as x approaches 0

当我测试F(X)= X^2点4,使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 

这里是我的问题,H公司和结果的列表:

  1. 什么是挑小时最好的办法,显然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之间有一个数字,这会给我一个更精确的结果,有没有办法找到这个数字,或者最少接近它。

ANSWERED

非常感谢您BobG。该应用程序目前计划使用两种形式,一种命令行PC应用程序。和一个Android应用程序。您将特别感谢关于页面的部分内容。如果你希望它会是开源的,但我不会发布链接到项目网站,直到我找出一些非常大的错误。目前我一直称它为Mathulator,但名称可能会因为已经有版权而改变,听起来很愚蠢。当候选发行版运行时,我一点也不知道,当时我不知道它是什么时候将会保持稳定。但如果我能实现我想要的一切,它将会非常强大。再次感谢。快乐编程。

+0

我得到了1E-7和1E-8的平均值更多的十进制小数。这就是5.4999999999999996E-8,得到的结果是8.000000080569821 – 2011-04-04 20:18:13

+0

参见[数值微分](http://en.wikipedia.org/wiki/Numerical_differentiation)。 – trashgod 2011-04-04 20:34:01

回答

3

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

数字食谱用C,第2版,出版社,Vetterling,Teukolsky,和弗兰纳里。这本书也有C++,Fortran和BASIC版本。可悲的是,没有Java版本存在。此外,我相信这本书已绝版,但可以在线购买某些版本的二手版(至少通过bn.com购买)。

第5.7节“数值衍生物” 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,vol.4,no.2,pp75-76。)

+0

我会研究这个,非常感谢你 – 2011-04-04 21:01:59

+0

非常感谢你,这个(当使用双打而不是单一的浮动)给我大多数功能的确切答案,我从来没有,虽然我会接近真正的答案只是一般接近估计。非常非常感谢你。这实际上给了我TI确切的浮点数,这是我正在寻找的。这帮助我克服了每一个小时,现在一直在寻找一个星期。下一个驼峰.....整合XD,应该很有趣,但我想我知道这一个 – 2011-04-05 01:41:20

2

阅读标题为“每个程序员应该知道什么是浮点数”(google为它)。然后你会看到大多数浮点值大约在计算机硬件中表示。

要进行没有此缺点的计算,请使用符号计算。但是这不像使用浮点一样有效。

要使浮点结果一致,请使用舍入至最近幂的10,例如0.1,0.01等。要了解何时应该停止apporximations,请在近似步骤中使用某种阈值来监视。例如,如果执行下一个近似步骤只产生。将001%更改为已计算的值,则无法继续使用近似值。

更新我有我的数值计算类很久以前,但我隐约记得,从其减去接近数字是非常糟糕的,因为如果数字非常接近,最可靠的数字被取消了,你有不可靠的数字。这正是您在减少h时发生的情况。在这些情况下建议的是替代减法和其他一些操作。例如,你可以切换到你的`f(x)扩展的某种系列。

我不太理解你的第二个问题,因为答案取决于你的要求 - “尽可能多你想要的”。

顺便说一句,您可能有更好的运气,找到您在math.stackexchange.com的问题的答案。

此外,访问链接通过thrashgod提供:Numerical differentiation

+0

我已经知道了所有这一切。我的问题是什么是最合适的h,以及如何缩放到任何尺寸 – 2011-04-04 20:40:39

+0

@The Dude I更新了答案。 – 2011-04-04 20:57:03

+0

啊谢谢你,我不知道math.stackexchange.com。 – 2011-04-04 21:00:42

0

我会用BigDecimal类这类计算的,虽然它不是一个回答你的问题,但它会真正提高浮点运算的精度。

+0

我想仅使用我的代码编写整个计算器。我不想写我自己的余弦和对数例程。我不得不因为BigDecimal不这样做。 – 2011-04-04 20:32:31

2

1 。浮点数(float和double)的精度取决于数字的绝对值。双打有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; 

反正这是一个近似值,也就是说,如果你试图计算sin(x)的在x = 1E9,你会得到H = 10的衍生物和结果将是完全错误的。但对于具有“接近零”的“有趣”部分的“常规”功能,这将工作得很好。

2.“h”越小,您对衍生物进行采样的点越精确,但您得到的衍生物的正确位数越少。我无法证明这一点,但我的直觉是,与h = x * 1e-8你得到7 = 15 - 8正确的数字,其中15是double的精度。

而且,这将是一个好主意,用一个“更对称”的公式,它提供了有关第二次多项式一个绝对正确的答案:

double derivative = (f(x+h) - f(x-h))/(2*h); 
+0

谢谢你的帮助,你说的对,这似乎更加精确。但是1E-7似乎是超精确的9个正确的0。所以让我问你这个。如果我接受了这个罪(1E9),并将其简化为弧度的最低项,这还是更准确的。 sin(pi)= sin(3pi)所以如果我简化为sin(1E9)= sin(不管这是什么),那么就用它作为我的x就是准确的。 – 2011-04-04 20:59:00

+0

是的,对于'sin(x)'的特定情况,您可以将'x'转换为范围(0; 2Pi),然后计算导数。但这已经是某种象征性的数学:你必须知道'f(x)'的周期是2Pi。你会为任何给定的功能做到这一点吗? – 2011-04-04 21:14:24

0

据Javadoc中,11位代表指数, 52位表示有效数字。无视指数,看起来你有52位玩家。所以如果你选择h = x * 2^-40,那么你在这里使用了40位,而你看到的精度是2^-12。根据您的需要调整这个比例。