2011-08-20 22 views
9

मैं प्रोजेक्ट यूलर समस्या 14 पर काम कर रहा हूं। यह मेरा समाधान है।यह हास्केल अभिव्यक्ति इतनी धीमी क्यों है?

import Data.List 

collatzLength :: Int->Int 
collatzLength 1 = 1 
collatzLength n | odd n = 1 + collatzLength (3 * n + 1) 
       | even n = 1 + collatzLength (n `quot` 2) 

maxTuple :: (Int, Int)->(Int, Int)->Ordering 
maxTuple (x1, x2) (y1, y2) | x1 > y1 = GT 
       | x1 < y1 = LT 
       | otherwise = EQ 

मैं निम्नलिखित चल रहा हूँ GHCi

की
maximumBy maxTuple [(collatzLength x, x) | x <- [1..1000000]] 

मुझे पता है कि अगर हास्केल सख्ती से मूल्यांकन किया है, इस पर समय O (n) की तरह कुछ होगा बाहर। चूंकि हास्केल आलसी मूल्यांकन करता है, ऐसा लगता है कि यह एन के कुछ निरंतर एकाधिक होना चाहिए। यह लगभग एक घंटे के लिए चल रहा है। बहुत अनुचित लगता है। क्या किसी को कोई विचार है क्यों?

+3

मैं नहीं दिख रहा है यही कारण है कि हास्केल के आलस्य इस की जटिलता को कोई फर्क चाहिए कलन विधि। – sepp2k

+2

आपका फ़ंक्शन 'collatzLength' पूंछ-पुनरावर्ती नहीं है। यह फ़ंक्शन को धीमा कर देता है और अनियंत्रित आवंटन का कारण बनता है। और आपका 'maxTuple'' fst की तुलना 'जैसा ही है। – fuz

+0

@sepp मुझे वास्तव में नहीं पता कि सूची समझ कैसे लागू की जाती है। यदि वे मानचित्र का उपयोग कर रहे हैं, यदि हास्केल ने कड़ाई से मूल्यांकन किया है, तो ऐसा लगता है कि इसे कई बार सूची से गुजरना होगा। –

उत्तर

22

आप मान रहे हैं कि collatzLength फ़ंक्शन को याद किया जाएगा। हास्केल स्वचालित ज्ञापन नहीं करता है। आपको खुद ऐसा करने की आवश्यकता होगी। data-memocombinators पैकेज का उपयोग कर एक उदाहरण यहां दिया गया है।

import Data.List 
import Data.Ord 
import qualified Data.MemoCombinators as Memo 

collatzLength :: Integer -> Integer 
collatzLength = Memo.arrayRange (1,1000000) collatzLength' 
    where 
    collatzLength' 1 = 1 
    collatzLength' n | odd n = 1 + collatzLength (3 * n + 1) 
        | even n = 1 + collatzLength (n `quot` 2) 

main = print $ foldl1' max $ [(collatzLength n, n) | n <- [1..1000000]] 

यह -O2 के साथ संकलित होने पर लगभग 1 सेकंड में चलता है।

1

अधिकतम सूची खोजने में सक्षम होने के लिए, संपूर्ण सूची का मूल्यांकन करने की आवश्यकता है।

तो 1 से 1000000 और collatzLength से collatzLength की गणना की जाएगी collatzLength रिकर्सिव है। सबसे बुरी बात यह है कि collatzLength की आपकी परिभाषा पूंछ-पुनरावर्ती भी नहीं है।

+0

यह उत्तर बिंदु को याद करता है। पूरी सूची * करता है * का मूल्यांकन किया जाना चाहिए, लेकिन 'collatzLength' के परिणामों को रिकॉर्ड करना (याद रखना), इसे ठीक से बढ़ाया जा सकता है * क्योंकि * इसे पुन: परिभाषित किया गया है। मुझे लगता है कि यह ज्ञान की गड़बड़ी है कि इस यूलर समस्या को व्यक्त करना है। –

+0

ठीक है, लेकिन उसने आलसी मूल्यांकन के बारे में पूछा। और मैंने कहा कि आलसी मूल्यांकन इसे यहां तेजी से नहीं बनाएगा क्योंकि हर चीज का मूल्यांकन किया जाना चाहिए (कम से कम एक बार) वैसे भी। लेकिन तुम सही हो! समस्या एक बार सब कुछ का मूल्यांकन नहीं कर रही है, समस्या एक बार से अधिक सब कुछ _more_ मूल्यांकन है। –

+0

आह, मैं देखता हूं कि आप कहां से आ रहे थे।आप भी सही हैं: पूरी सूची का मूल्यांकन किया जाना चाहिए, इसलिए आलस्य वास्तव में मदद नहीं करेगा; पोस्टर का भ्रम स्पष्ट रूप से आलसी मूल्यांकन को स्पष्ट रूप से समझने से नहीं आया, मानते हुए कि इसमें ज्ञापन जादू शामिल है जो यह नहीं करता है। –

0

cL के लिए collatzLength

cL!!n खड़ा के लिए कम है collatzLength n

cL :: [Int] 
cL = 1 : 1 : [ 1 + (if odd n then cL!!(3*n+1) else cL!!(n `div` 2)) | n <- [2..]] 

सरल टेस्ट:

ghci> cL !! 13 
10 
+0

असल में, यह ऐसी सूची का उपयोग करता है जो 'collatzLength' को याद करता है क्योंकि यह स्वयं ही बना है। लेकिन जब आप 'सीएल के लिए निष्पादन के आदेश का पता लगाने की कोशिश करते हैं तो यह दिमागी दबदबा है !! 3', जो 'सीएल पर निर्भर करता है !! 10', सूची में बाद का तत्व जिसे पहले मूल्यांकन किया जाएगा! –

+0

@ डैन बर्टन, सबसे खराब यह है कि यह धीरे-धीरे चलता है, शायद कारण (!!)। – wenlong

+0

हां, '!!' * ए (एन) * समय जटिलता के एक हिस्से को एल्गोरिदम के दिल में जोड़ता है (इसके विपरीत, एक ज्ञापन फ़ंक्शन * ओ (1) * होना चाहिए या * ओ (लॉग एन) * लुकअप के लिए सबसे खराब), इसलिए बड़े 'एन' के लिए आप निश्चित रूप से एक बड़ी मंदी देखेंगे। –

संबंधित मुद्दे