2017-10-30 49 views
6

Tôi đã viết hàm isPrime. Nó kiểm tra nếu một số đã cho là số nguyên tố hay không. Danh sách "nguyên tố" cuối cùng được cung cấp riêng.chức năng hợp nhất chậm hơn nhiều

prime :: [Integer] 
prime = 2 : filter isPrime [3..] 
isPrime :: Integer -> Bool 
isPrime n | n < 2 = False 
isPrime n = all (\p -> n `mod` p /= 0) . takeWhile ((<=n) . (^2)) $ prime 

Tôi nghĩ tốt hơn nên hợp nhất hai hàm thành một nếu có thể..để tôi củng cố isPrime và nhập thành một hàm isPrime2. Nhưng hiệu suất của isPrime2 rất tệ.

isPrime2 :: Integer -> Bool 
isPrime2 n | n < 2 = False 
isPrime2 n = all (\p -> n `mod` p /= 0) . takeWhile ((<=n) . (^2)) $ 2 : filter isPrime2 [3..] 

isPrime 40000000000000000001

=> 0,5 giây

isPrime2 40000000000000000001

=> 19,8 giây

máy của tôi là Ubuntu 17.10 x86-64. Tôi đang sử dụng ghc 8.2.1. Có ai biết tại sao không?

+0

Đoán của tôi là vì 'nguyên tố' là hằng số, nó được ghi nhớ, trong khi' isPrime2' là hàm, vì vậy nó không có. Đó chỉ là một dự đoán, tuy nhiên ... – MathematicalOrchid

+0

Cảm ơn! Lời giải thích của bạn đã cho tôi những hiểu biết. – eii0000

+0

@ eii0000 là bạn thử nghiệm nó biên soạn hoặc giải thích? nó so sánh như thế nào nếu bạn đơn giản hóa 'isPrime2 n' là' 'tất cả (\ p -> n' mod' p/= 0). takeWhile ((<= n). (^ 2)) $ 2: [3,5 ..] ''? –

Trả lời

6

Đoạn đầu tiên sẽ chỉ giữ một danh sách prime giây trong bộ nhớ.

Đoạn thứ hai sẽ tính toán prime riêng của mình cho đến n^2mỗi lần gọiisPrime2 được gọi. Các số nguyên tố được phát hiện trước đó bị loại bỏ và được tính toán lại từ đầu ở mọi cuộc gọi. Kể từ isPrime2 là đệ quy điều này dẫn đến một cú đánh.

Một cách tiếp cận trung gian có thể được điều này một:

isPrime2 :: Integer -> Bool 
isPrime2 m = isPrime m 
    where 
    prime :: [Integer] 
    prime = 2 : filter isPrime [3..] 
    isPrime :: Integer -> Bool 
    isPrime n | n < 2 = False 
    isPrime n = all (\p -> n `mod` p /= 0) . takeWhile ((<=n) . (^2)) $ prime 

này sẽ recompute prime tại mỗi cuộc gọi của isPrime2, nhưng sẽ không dẫn đến một đòn-up vì mỗi tiếng gọi của khu vực nội isPrime sẽ chia sẻ cùng một danh sách trong số prime s.

+0

tuyệt vời ... isPrime2 của bạn là 0,5 giây quá .. Cảm ơn! – eii0000

+0

Sẽ không GHC thường nổi 'nguyên tố' và' isPrime' ra mức cao nhất trong quá trình tối ưu hóa? –

+0

@BenjaminHodgson Không, GHC là bảo thủ ở đây vì nó không phải luôn luôn là một tối ưu hóa. Tôi tin rằng sự biến đổi này được gọi là (hoặc liên quan đến) sự biến đổi "đầy lười biếng", nơi '\ x -> để y = ... trong ....' trở thành 'cho y = ... trong \ x ->. ..' với điều kiện 'y' không phụ thuộc vào' x'. Các ngữ nghĩa được bảo tồn, nhưng thật khó để dự đoán cái nào có hiệu suất tốt nhất (IIRC). – chi

Các vấn đề liên quan