2017-04-15 53 views
1

你好,程序員比我好。這不是一個大問題,但我對這個功能很好奇,更重要的是它有時會給出結果。所以我爲包含負指數的家庭作業定義了遞歸功能函數。對於正值和0,它工作正常,但是當我輸入一些負值時,答案真的很奇怪。下面是函數:遞歸功能函數給出奇怪的答案

public static double Power(int base, int exp){ 
    if (exp == 0) 
     return 1.0; 
    else if(exp >=1) 
     return base * Power(base, exp - 1); 
    else 
     return (1.0/base) * Power(base, exp + 1);    
} 

因此,對於呼叫電源(5,-1)函數返回0.2,像它應該。但是對於Power(5,-2)這個函數,函數返回值爲0.04000000000000001,而不是0.04。 再一次,這不是一個很大的交易,因爲它是作業而不是「現實生活」,但只是好奇爲什麼發生這種情況。我認爲這與計算機內存或雙重值的存儲方式有關,但真的不知道。謝謝大家!

PS,這是用Java編碼使用Netbeans如果有所作爲。

+0

湯姆斯科特做了一個偉大的視頻解釋這個https://www.youtube.com/watch?v=PZRI1IfStY0 – SpiderPig

+0

http://stackoverflow.com/questions/8511312/java-double-variables-have-strange-values –

+0

重新開放以指出減少此特定程序的舍入誤差的策略。 –

回答

0

仔細組織您的算術可以減少浮點舍入誤差。一般來說,您希望最小化舍入操作的次數以及對舍入結果進行的計算次數。

我做了小改動,以你的函數:

public static double Power(int base, int exp) { 
    if (exp == 0) 
     return 1.0; 
    else if (exp >= 1) 
     return base * Power(base, exp - 1); 
    else 
     return (1.0/Power(base, -exp)); 
    } 

爲您的測試情況下,Power(5, -2),這樣做只有一個圓形的計算,在該遞歸的頂分工。它最接近1/25.0的兩倍,打印爲0.04。

0

這是1990年的事情

這將可能是一個被忽略的或有爭議的答案,但我覺得它需要說。

其他人已將注意力集中在「浮點」計算(例如涉及一個或多個「雙打」數字的計算)上的消息近似爲數學。

我對這個答案的關注點在於,即使在普通Java代碼中使用這種方式,並且在大多數編程語言中的普通代碼中,數字如0.1的計算不必是近似值。


幾種語言治療號碼,如0.1爲有理數,兩個整數之間的比率(分子分母上,在這種情況下1超過10或十分之一),就像他們在學校的數學。只包含整數和有理數的計算是100%準確的(忽略整數溢出和/或OOM)。

不幸的是,如果分母變得太大,理性計算會變得很慢。


有些語言採取妥協的立場。他們把一些理性看作是理性的(所以100%的準確性),只有100%的準確性纔會放棄,當理性的計算在病態上是緩慢的時候,轉換爲漂浮。

例如,這裏是一個相對較新的和前瞻性的編程語言的一些代碼:

sub Power(\base, \exp) { 
    given exp { 
     when 0  { 1.0        } 
     when * >= 1 { base  * Power(base, exp - 1) } 
     default  { 1.0/base * Power(base, exp + 1) } 
    } 
} 

這在重複這個其他語言代碼。

現在使用這個函數來獲得結果的指數的列表:

for 1000,20,2,1,0,-1,-2,-20,-1000 -> \exp { say Power 5, exp } 

Running this code in glot.io顯示:

9332636185032188789900895447238171696170914463717080246217143397959 
6691097577563445444032709788110235959498993032424262421548752135403 
2394841520817203930756234410666138325150273995075985901831511100490 
7962651131182405125147959337908051782711254151038106983788544264811 
1946981422866095922201766291044279845616944888714746652800632836845 
2647429261829862165202793195289493607117850663668741065439805530718 
1363205998448260419541012132296298695021945146099042146086683612447 
9295203482686461765792691604742006593638904173789582211836507804555 
6628444273925387517127854796781556346403714877681766899855392069265 
4394240087119736747017498626266907472967625358039293762338339810469 
27874558605253696441650390625 
95367431640625 
25 
5 
1 
0.2 
0.04 
0.000000000000010 
0 

上述結果是100%準確 - 直到最後的指數,-1000。我們可以看到在語言上的準確率100%放棄,如果我們檢查結果的類型(使用WHAT):

for 1000,20,2,1,0,-1,-2,-20,-1000 -> \exp { say WHAT Power 5, exp } 

顯示:

(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Rat) 
(Num) 

轉換Rat秒(默認理性型)成FatRat S(任意精度理性型)避免不準確甚至經病理大分母:

sub Power(\base, \exp) { 
    given exp { 
     when 0  { 1.0.FatRat        } 
     when * >= 1 { base   * Power(base, exp - 1) } 
     default  { 1.0.FatRat/base * Power(base, exp + 1) } 
    } 
} 

這產生同樣顯示爲我們的原代碼,除了它出來作爲最後的計算:

0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011 

我不知道這是正確的,但是,AIUI,它應該是。