2012-07-06 56 views
7

我有一個功能:C#isPowerOf功能

static bool isPowerOf(int num, int power) 
{ 
     double b = 1.0/power; 
     double a = Math.Pow(num, b); 
     Console.WriteLine(a); 
     return a == (int)a; 
} 

我插入用於分析的打印功能。

如果我調用該函數:

isPowerOf(25, 2) 

它,因爲5^2等於25 返回true但是,如果我叫16807,這是7^5,接下來的路:

isPowerOf(16807, 5) 

在這情況下,它打印'7',但a == (int)a返回false。

你能幫忙嗎?謝謝!

+6

強制鏈接到[每個計算機科學家應該知道的浮點算術](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – AakashM 2012-07-06 09:47:12

+1

每個人都會建議更好浮點比較,但IMO問題的根源在於這裏的算法。 – harold 2012-07-06 09:48:36

回答

6

嘗試使用小小量舍入誤差:

return Math.Abs(a - (int)a) < 0.0001; 

正如哈羅德認爲,這將是更好的一輪的情況下a恰好是比整數值略小,像3.99999:

return Math.Abs(a - Math.Round(a)) < 0.0001; 
+0

它現在可以工作,但是怎麼會這樣7!=(int)7? – Novak 2012-07-06 09:45:40

+0

@GuyDavid:它由於舍入錯誤,你得到的數字不是7,但它是7.000000001或類似的東西 – Dani 2012-07-06 09:46:50

+0

@Guy大衛嘗試:Console.WriteLine((int)a); – 2012-07-06 09:50:37

2

如果調試代碼,然後你可以看到,在第一個比較:

isPowerOf(25, 2) 

一個持有5.0 這裏5.0 == 5 = A拿着7.0000000000000009

,自7.0000000000000009 != 7 =>你得到虛假>這就是爲什麼你會得到真正的

和第二isPowerOf(16807, 5)

。和Console.WriteLine(一)被截斷/舍入的雙並只顯示7

這就是爲什麼你需要達尼的解決方案

2

Math.Powdouble小號操作比較像最近的值,所以舍入誤差進入在生根時玩。如果要檢查是否已找到一個確切的功率:

  • 執行Math.Pow作爲當前,提取根
  • 結果爲最接近的整數
  • 提出這個整數的提供的電力,並檢查你得到提供的目標。募集到的整數次冪
5

比較是解決這個問題已經被提出時Math.Pow是準確的在int範圍內的數字,但究竟是這裏的問題是,浮點不應該在所有參與。你需要一個涉及整數的問題的確切答案,而不是對本質上不準確的測量進行計算的近似值。

那該怎麼辦呢?

,想到的第一件事是個騙子:

double guess = Math.Pow(num, 1.0/power); 
return num == exponentiateBySquaring((int)guess, power) || 
     num == exponentiateBySquaring((int)Math.Ceil(guess), power); 
     // do NOT replace exponentiateBySquaring with Math.Pow 

它會工作,只要guess小於1點了。但我不能保證它始終適用於您的輸入,因爲並不總是滿足這個條件。

因此,下面介紹一下:中base的二元搜索(首先搜索上邊界的變體),其結果最接近num。當且僅當最接近的答案等於num(並且它們都是整數,因此該比較是乾淨的),那麼numpower次冪。除非有溢出(不應該有),否則應該始終有效。

+0

確實如此,整數和浮點數是不同的類型有很好的理由。 – 2012-07-06 11:03:06