2012-07-06 58 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