2011-04-04 68 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。根據您的需要調整這個比例。