简体   繁体   English

Java估计一个点的导数

[英]Java estimate a derivative at a point

I am currently writing a calculator application. 我目前正在编写一个计算器应用程序。 I am trying to write a derivative estimator into it. 我试图在其中写一个导数估计器。 The formula below is a simple way to do it. 下面的公式是一种简单的方法。 Normally on paper you would use the smallest h possible to get the most accurate estimate. 通常,在纸上,您将使用尽可能小的h来获得最准确的估计。 The problem is doubles can't handle adding really small numbers to comparatively huge numbers. 问题是,双打无法处理将较小的数字加到相对较大的数字。 Such as 4+1E-200 will just result in 4.0. 例如4 + 1E-200只会得到4.0。 Even if h was just 1E-16, 4+1E16 will in fact give you the right value but doing math it it is inaccurate because anything after the 16th place is lost and rounding can't happen correctly. 即使h只是1E-16,实际上4 + 1E16也会为您提供正确的值,但是在进行数学运算时这是不准确的,因为第16位之后的所有内容都会丢失,并且舍入不能正确进行。 I have heard the general rule of thumb for doubles is 1E-8 or 1E-7. 我听说双打的一般经验法则是1E-8或1E-7。 The issue with this is large numbers wont work as 2E231+1E-8 will just be 2E23, the 1E-8 will be lost because of size issues. 这个问题是大数字将不起作用,因为2E231 + 1E-8将会是2E23,1E-8将由于尺寸问题而丢失。

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

When I test f(x)=x^2 at the point 4 so f'(4), it should be exactly 8 now I understand that I will probably never get exactly 8. but I the most accurate seems to be around 1E-7 or 1E8 the funny thing is 1E-9 all the to 1E-11 give the same answer. 当我在点4这样f'(4)上测试f(x)= x ^ 2时,它应该恰好是8,现在我知道我可能永远也不会精确得到8。但是我最准确的似乎是1E- 7或1E8有趣的是1E-9到1E-11都给出相同的答案。 Here is a list of h's and results for f(x)=x^2 at x=4 这是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

Here are my questions: 这是我的问题:

  1. What is the best way to pick h, obviously 1E-8 or 1E-7 make sense but how can I pick an h based off of x, so that it will work with any sized number even if x is 3.14E203 or 2E-231. 最佳选择h的最佳方法是什么,显然1E-8或1E-7是有意义的,但是我如何基于x来选择h,因此即使x是3.14E203或2E-231,它也可以使用任何大小的数字。
  2. How many decimals of precision should I account for. 我应该计算多少位精度。
  3. Do you have any idea how Texas instruments does it, the TI 83, 84, and Inspire can numerically figure out derivatives to 12 decimals or precision and almost always be right, but the maximum precision of their numbers is 12 digits anyway and those calculators are non CAS so they aren't actually deriving anything 您是否知道德州仪器是如何做到的,TI 83、84和Inspire可以在数值上计算出12位小数或精度的导数,并且几乎总是正确的,但是无论如何,其数字的最大精度是12位,而那些计算器是非CAS,因此他们实际上并没有派生任何东西
  4. Logically there is a number somewhere between 1E-7 and 1E-8 that will give me a more precise result, is there any way to find that number, or at least get close to it. 从逻辑上讲,在1E-7和1E-8之间会有一个数字,它将为我提供更精确的结果,是否可以找到该数字,或者至少可以接近该数字。

ANSWERED 回答

Thank you very much BobG. 非常感谢BobG。 The application is currently planned to be in 2 forms, a command line PC application . 目前,该应用程序计划采用两种形式,即命令行PC应用程序。 And an Android application. 还有一个Android应用程序。 You will be mentioned in the special thanks to portions of the About page. 特别感谢您的“关于”页面部分。 If you would like it will be open source but I am not posting links to the project site until I work out some very very large bugs. 如果您希望它是开源的,但是在我解决一些非常大的错误之前,我不会发布指向项目站点的链接。 At the moment I have been calling it Mathulator, but the name will likely change because there is already a copyright on it and it sounds stupid.I have no clue when the release candidate will be running, at the moment I have no clue when it will be stable. 目前我一直称其为Mathulator,但名称可能会更改,因为它已经拥有版权并且听起来很愚蠢。我不知道何时发布候选版本将要运行,目前我不知道何时发布会稳定的。 But it will be very powerful if I can implement everything I want too.Thanks again. 但是如果我也能实现我想要的一切,它将非常强大。再次感谢。 Happy Programming. 编程愉快。

There's a book that answers this question (and others like it): 有一本书可以回答这个问题(和其他类似的问题):

Numerical Recipes in C , 2nd Edition, by Press, Vetterling, Teukolsky, and Flannery. C ,第二版的数字食谱 ,出版社,Vetterling,Teukolsky和Flannery。 This book also comes in C++, Fortran, and BASIC versions, as well. 本书还提供C ++,Fortran和BASIC版本。 Sadly, no Java version exists. 可悲的是,不存在Java版本。 Additionally, I believe this book is out of print, but it is possible to buy used versions of some of the flavors online (at least through bn.com.) 此外,我认为这本书已经绝版,但可以在线购买某些口味的二手版本(至少通过bn.com)。

Section 5.7, "Numerical Derivatives," p. 第5.7节“数值导数”,第2页。 186 explains exactly the problem you're seeing with numerical derivatives and the math behind why it happens, along with a function for how to compute a numerical derivative properly (in C, but it should be easy to translate to Java). 186精确地解释了您在使用数值导数时遇到的问题及其发生原因的数学原理,以及用于正确计算数值导数的函数(在C语言中,但应易于转换为Java)。 A summary of their simple approximation is presented here: 这里给出了它们的简单近似的总结:

1) Numerically, you're better off computing the symmetric version: 1)从数字上讲,最好计算对称版本:

f'(x) = (f(x + h) - f(x - h)) / 2h f'(x)=(f(x + h)-f(x-h))/ 2h

2) h should be approximately (sigma_f)^(1/3) * x_c 2)h应该大约是(sigma_f)^(1/3)* x_c

where 哪里

sigma_f =~ fractional accuracy of the computation of f(x) for simple functions sigma_f =〜 对于简单函数 ,f(x)计算的分数精度

x_c =~ x, unless x is equal to zero. x_c =〜x,除非x等于零。

However, this does not result in optimal derivatives, as the error is ~ (sigma_f)^(2/3). 但是,这不会导致最优导数,因为误差为〜(sigma_f)^(2/3)。 A better solution is Ridders' algorithm, which is presented as the C program in the book (ref. Ridders, CJF 1982, Advances in Engineering Software, vol. 4, no. 2, pp 75-76.) 更好的解决方案是Ridders算法,该算法在本书中以C程序的形式提供(参见Ridders,CJF 1982,Advances in Engineering Software,第4卷,第2期,第75-76页)。

Read paper titled "What every programmer should know about floating point" (google for it). 阅读标题为“每个程序员应了解的浮点知识”的论文(为此,请使用Google)。 Then you'll see that most of the floating values are represented approximately in computer hardware. 然后,您将看到大多数浮点值大约在计算机硬件中表示。

To make calculations without this drawback, use symbolic calculation. 要进行计算而没有此缺点,请使用符号计算。 But this is not as efficient as using floating point. 但这不如使用浮点数有效。

To make floating point results consistent, use rounding to nearest power of 10, eg, 0.1, 0.01, etc. To understand when you should stop apporximations, use some kind of threshold to watch for during approximation steps. 要使浮点结果一致,请使用四舍五入到最接近的10的幂,例如0.1、0.01等。要了解何时应停止逼近,请在近似步骤中使用某种阈值来注意。 Eg, if performing next approximation step yields only .001% change to already computed value, there's no sense to continue approximations. 例如,如果执行下一个逼近步骤,仅对已计算的值产生0.001%的变化,则没有理由继续逼近。

Update I had my numerical computation classes long ago, but I can vaguely recall that substracting close numbers is very bad, because if numbers are very close, most reliable digits are cancelled out and you have unreliable digits. 更新我很早以前就有数值计算课程,但是我可以隐约地记得减去接近数非常不好,因为如果数字非常接近,最可靠的数字就会被抵消,而您的数字也不可靠。 This is exactly what happens when you decreasing h . 当您减小h时,这正是发生的情况。 What is suggested in these situations is substitute substraction with some other operations. 在这些情况下,建议将减法替换为其他一些操作。 For example, you can switch to some kind of series to which your `f(x) expands. 例如,您可以切换到f(x)扩展到的某种系列。

I don't quite understand your 2nd question, because answer depends on your requirements -- "as many as you wish". 我不太了解您的第二个问题,因为答案取决于您的要求-“您所希望的数量”。

By the way, you might have better luck with finding answers to your questions at math.stackexchange.com. 顺便说一句,如果您在math.stackexchange.com上找到问题的答案,可能会比较幸运。

Additionally, visit link provided by thrashgod : Numerical differentiation 此外,访问thrashgod提供的thrashgod数值微分

1.The precision of floating-point numbers (floats and doubles) depends on the number's absolute value. 1.浮点数(浮点数和双精度数)的精度取决于数字的绝对值。 Doubles have ~15 digits of precision, so you can add 1 + 1e-15 , but 10 + 1e-15 will likely be 10 again, so you will have to do 10 + 1e-14 . 双精度数的精度约为15位,因此您可以加1 + 1e-15 ,但是10 + 1e-15可能又是10,因此您必须做10 + 1e-14 To get a meaningful result, I would recommend you to multiply that very 1e-8 by the original number's absolute value, this will give you about 7 correct digits in the derivative. 为了获得有意义的结果,我建议您将1e-8乘以原始数字的绝对值,这将为您提供7个正确的派生数字。 Something like: 就像是:

double h = x * 1e-8;
double derivative = (f(x+h) - f(x)) / h;

Anyway this is an approximation, say, if you try to calculate the derivative of sin(x) at x=1e9, you will get h=10 and the result will be all wrong. 无论如何,这是一个近似值,例如,如果您尝试计算x = 1e9时sin(x)的导数,则将得到h = 10,结果将全为错误。 But for "regular" functions that have the "interesting" part near zero this will work well. 但是对于“有趣的”部分接近零的“常规”函数,它将很好地工作。

2.The less is "h", the more precise is the point at which you sample the derivative, but the fewer correct digits of the derivative you get. 2.“ h”越小,采样导数的点越精确,但是得到的导数的正确位数越少。 I can't prove this but my gut feeling is that with h = x * 1e-8 you get 7 = 15 - 8 correct digits where 15 is the double 's precision. 我无法证明这一点,但是我的直觉是,当h = x * 1e-8您将获得7 = 15 - 8 h = x * 1e-8正确数字,其中15是double的精度。

Also, it would be a good idea to use a "more symmetric" formula, it gives an absolutely correct answer on second order polynomials: 同样,使用“更对称”的公式也是一个好主意,它对二阶多项式给出了绝对正确的答案:

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

My question is what is the most appropriate h , and how can it be scaled to any size. 我的问题是什么是最合适的h ,如何将其缩放为任意大小。

As noted in Numerical Differentiation , a suitable choice for h is sqrt(ɛ) * x , where ɛ is the machine epsilon . 数值微分中所述, h的合适选择是sqrt(ɛ) * x ,其中ɛ机器epsilon

我不会将BigDecimal类用于此类计算,尽管它不能回答您的问题,但确实可以提高浮点运算的精度。

According to the Javadoc, 11 bits represent the exponent and 52 bits represent the significant digits. 根据Javadoc,11位代表指数,而52位代表有效数字。 Disregarding the exponent, it seems you have 52 bits to play with. 忽略指数,似乎您有52位要玩。 So if you choose h = x * 2^-40, you've used 40 bits here, and the precision you gonna see is 2^-12. 因此,如果您选择h = x * 2 ^ -40,则在这里使用了40位,您将看到的精度为2 ^ -12。 Adjust this ratio to your needs. 根据您的需要调整此比例。

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

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