2012-07-06 44 views
7

tôi có chức năng tiếp theo:C# isPowerOf chức năng

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; 
} 

tôi chèn các chức năng in để phân tích.

Nếu tôi gọi hàm:

isPowerOf(25, 2) 

Nó trở thành sự thật kể từ 5^2 bằng 25. Nhưng, nếu tôi gọi 16.807, đó là 7^5, cách tiếp theo:

isPowerOf(16807, 5) 

Trong này trường hợp, nó in '7' nhưng a == (int)a trả về false.

Bạn có thể trợ giúp không? Cảm ơn!

+6

Liên kết bắt buộc với [Điều mà mọi nhà khoa học máy tính cần biết về số học dấu chấm động] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – AakashM

+1

Mọi người sẽ đề xuất tốt hơn so sánh điểm trôi nổi, nhưng IMO gốc của vấn đề là thuật toán ở đây. – harold

Trả lời

6

Hãy thử sử dụng một epsilon nhỏ cho các lỗi làm tròn:

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

Như harold gợi ý, nó sẽ được tốt hơn để làm tròn trong trường hợp a sẽ xảy ra là hơi nhỏ hơn so với giá trị số nguyên, như 3,99999:

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

Nó hoạt động bây giờ, nhưng làm thế nào mà 7! = (Int) 7? – Novak

+0

@GuyDavid: Đó là do lỗi làm tròn, số bạn nhận được không phải là 7, nhưng là 7.000000001 hoặc một cái gì đó tương tự như vậy – Dani

+0

@Guy David thử: Console.WriteLine ((int) a); –

2

Nếu bạn gỡ lỗi mã và sau đó bạn có thể thấy rằng trong so sánh đầu tiên:

isPowerOf(25, 2) 

một đang nắm giữ 5.0 Đây 5,0 == 5 => đó là lý do tại sao bạn sẽ có được đúng

và trong 2 isPowerOf(16807, 5)

một đang nắm giữ 7.0000000000000009

và kể từ 7.0000000000000009 != 7 => bạn đang nhận sai. và Console.WriteLine (a) được cắt xén/làm tròn đôi và chỉ hiển thị 7

Đó là lý do tại sao bạn cần phải so sánh giá trị gần như trong dung dịch Dani

2

Math.Pow hoạt động trên double s, lỗi để làm tròn đi vào chơi khi dùng rễ. Nếu bạn muốn kiểm tra xem bạn đã tìm thấy một sức mạnh chính xác:

  • thực hiện Math.Pow như hiện nay, để giải nén vào thư mục gốc
  • vòng kết quả số nguyên gần nhất
  • tăng số nguyên này đến cung cấp điện, và kiểm tra bạn nhận được mục tiêu cung cấp. Math.Pow sẽ chính xác cho các số trong phạm vi của int khi tăng để nguyên quyền hạn
5

So sánh mà khắc phục vấn đề đã được đề xuất, nhưng những gì thực sự là vấn đề ở đây là điểm nổi không nên tham gia ở tất cả các. Bạn muốn có một câu trả lời chính xác cho một câu hỏi liên quan đến số nguyên, không phải là một phép tính xấp xỉ được thực hiện trên các phép đo vốn không chính xác.

Vậy làm cách nào khác để thực hiện điều này?

Việc đầu tiên mà nói đến cái tâm là một cheat:

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 

Nó sẽ làm việc miễn là guess là ít hơn 1 tắt. Nhưng tôi không thể đảm bảo rằng nó sẽ luôn luôn làm việc cho đầu vào của bạn, bởi vì điều kiện đó không phải lúc nào cũng được đáp ứng. Vì vậy, đây là điều tiếp theo mà đến với tâm trí: một tìm kiếm nhị phân (biến thể mà bạn tìm kiếm ranh giới trên đầu tiên) cho base trong exponentiateBySquaring(base, power) mà kết quả là gần nhất với num. Nếu và chỉ khi câu trả lời gần nhất bằng num (và chúng là cả hai số nguyên, vì vậy so sánh này là sạch), sau đó num là một điện thoại power -th. Trừ khi có tràn (không nên có), mà nên luôn luôn làm việc.

+0

Có thực sự, có những lý do chính đáng tại sao số nguyên và số dấu phẩy động là các loại riêng biệt. –