2010-10-20 108 views
4

我:哈斯克爾:不能使用getCPUTime

main :: IO() 
main = do 
    iniciofibonaccimap <- getCPUTime 
    let fibonaccimap = map fib listaVintesete 
    fimfibonaccimap <- getCPUTime 
    let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap))/(10^12) 
    printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double) 

listaVintesete :: [Integer] 
listaVintesete = replicate 100 27 

fib :: Integer -> Integer 
fib 0 = 0 
fib 1 = 1 
fib n = fib (n-1) + fib (n-2) 

*Main> main 
Computation time fibonaccimap: 0.000 sec 

我不明白爲什麼會這樣。 幫我謝謝。

回答

0

10^12是一個整數,這迫使的fromIntegral值是一個整數,這意味着difffibonaccimap被分配一個舍入的值,所以它的0,如果時間小於半秒。 (這是我的猜測,無論如何,我沒有時間去研究它。)

+1

雖然這不是真的,因爲'(/)'的類型是'分數a => a - > a - > a';事實上,由於他強迫'difffibonaccimap'在下一行是'Double',因此'10^12'必須是雙倍。 – 2010-10-20 15:26:43

+0

Adam只是誤解了'(^)'的類型,它是'(數字a,積分b)=> a - > b - > a'。 「Num a」類中的結果使得Double成爲可能。 (**):: Floating a => a - > a - > a'使得許多人錯誤地認爲'(^)'是'(**)'的整數版本,這不是一個不合理的誤解。 – 2010-10-20 23:51:26

+0

@TomMD:你有我。我假設'(^)'是'積分a => a - > a - > a'或類似的東西。 – 2010-10-21 00:19:38

7

Haskell是懶惰的。該行你

let fibonaccimap = map fib listaVintesete 

請求計算實際上並沒有發生,直到你以某種方式使用的fibonaccimap值。因此,爲了測量使用的時間,您需要介紹一些會強制程序執行實際計算的內容。

ETA:我最初建議打印最後一個元素來強制評估。正如TomMD指出的那樣,這遠不夠好 - 我強烈建議閱讀他的迴應,以獲得處理這段特定代碼的實際工作方式。

+0

謝謝,沒錯,懶惰的評價。 – Gmp 2010-10-20 18:11:25

+0

這個答案不正確。打印列表中的最後一個元素不會強制評估列表的其餘部分。請看我的回答和評論。 – 2010-10-21 05:50:44

+0

@TomMD當然你是對的。我的錯。 – 2010-10-21 06:26:52

4

我懷疑你是lazy evaluation的「受害者」。什麼都不會強制在定時調用之間對fibonaccimap進行評估,所以不計算。

編輯 我懷疑你想基準你的代碼,在這種情況下,應該指出的是,有better waysdo this更可靠。

+1

不,不要執行打印列表中最後一個元素的黑客作業。這不會強制評估列表中的任何其他元素。 – 2010-10-21 05:51:39

+0

TomMD:謝謝!固定。 – gspr 2010-10-21 09:09:56

7

正如其他人所說,這是由於懶惰的評價。要強制評估你應該使用deepseq包和BangPatterns

{-# LANGUAGE BangPatterns #-} 
import Control.DeepSeq 
import Text.Printf 
import System.CPUTime 

main :: IO() 
main = do 
iniciofibonaccimap <- getCPUTime 
let !fibonaccimap = rnf $ map fib listaVintesete 
fimfibonaccimap <- getCPUTime 
let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap))/(10^12) 
printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double) 
... 

在上面的代碼你應該注意三件事情:

  1. 它編譯(模的你在上面定義函數...)。當你發佈問題的代碼請確保它運行(低價,你應該包括進口)
  2. 使用rnfdeepseq。這會強制評估列表中的每個元素。
  3. !fibonaccimap上的爆炸圖案,意思是「現在就做,不要等待」。這迫使名單被評估爲弱頭正常形式(當然,基本上只是第一個構造函數(:))。如果沒有這個,rnf函數本身將保持未評估狀態。

結果造成:

$ ghc --make ds.hs 
$ ./ds 
Computation time fibonaccimap: 6.603 sec 

如果你打算做標杆,你也應該使用優化(-O2)和Criterion包,而不是getCPUTime

+0

感謝您的幫助,我不知道標準,我試圖安裝,但不能,我會試圖找出發生了什麼。謝謝 – Gmp 2010-10-20 21:13:49

+0

@user好,請使用Criterion。謹防使用'print'和/或'show'這些完全不正確的「快速和骯髒」的建議。打印此列表中的最後一個元素不會強制計算任何其他元素!在我的示例中(沒有優化),將結果從6.6秒改爲0.403秒。 – 2010-10-21 05:48:51

0

懶惰的評價實際上已經讓你感到困擾,正如其他答案所說的那樣。具體而言,'let'不強制對錶達式進行評估,它只是對變量進行範圍。計算實際上不會發生,直到它的值被某些東西所要求,這可能不會發生,直到實際的IO操作需要它的值。所以你需要在你的getCPUTime評估之間放置你的print語句。當然,這也會得到在那裏用於打印的CPU CPU時間,但大部分打印時間都在IO上等待。 (終端很慢)

+1

他從不打印他的結果,打印是經過的時間。而且,打印結果是一種非常黑客的強制評估方式,人們最好學習並行和deepseq軟件包。 – 2010-10-20 23:53:06

+0

謝謝大家,很高興知道很多人對我說過,我有很多問題,不知道該問誰。 TomMD的回覆是正確的,我測試過了,我很想知道Criterion,但我無法安裝。現在我將完成該程序的其他步驟,然後再回來嘗試Criterion,它對於並行編程看起來非常有趣。 我正在做這個程序來與喬阿姆斯特朗書中描述的其他Erlang進行比較。 當然,我有更多的問題... 謝謝 – Gmp 2010-10-21 13:35:44

+0

@TomMD哎呀錯過了。 – Edward 2010-10-21 20:46:08