2012-07-02 9 views
17

solrize # हास्केल में इस कोड के एक संस्करण के बारे में एक प्रश्न पूछा और मैंने कुछ अन्य मामलों की कोशिश की और यह सोच रहा था कि क्या हो रहा था। मेरी मशीन पर "तेज़" कोड ~ 1 सेकंड लेता है और "धीमा" कोड ~ 1.3-1.5 लेता है (सब कुछ ghc -O2 के साथ संकलित किया जाता है)।'लॉग x/log 10` से' लॉगबेस 10 x` धीमा क्यों है, भले ही विशिष्ट हो?

import Data.List 

log10 :: Double -> Double 
--log10 x = log x/log 10 -- fast 
--log10 = logBase 10 -- slow 
--log10 = barLogBase 10 -- fast 
--log10 = bazLogBase 10 -- fast 
log10 = fooLogBase 10 -- see below 

class Foo a where 
    fooLogBase :: a -> a -> a 

instance Foo Double where 
    --fooLogBase x y = log y/log x -- slow 
    fooLogBase x = let lx = log x in \y -> log y/lx -- fast 


barLogBase :: Double -> Double -> Double 
barLogBase x y = log y/log x 

bazLogBase :: Double -> Double -> Double 
bazLogBase x = let lx = log x in \y -> log y/lx 


main :: IO() 
main = print . foldl' (+) 0 . map log10 $ [1..1e7] 

I'd've आशा व्यक्त की कि GHC log y/log x, के रूप में बिल्कुल वही बात में logBase x y चालू करने के लिए जब विशेष में सक्षम होगा। यहां क्या हो रहा है, और logBase का उपयोग करने का अनुशंसित तरीका क्या होगा?

+3

ghc कुछ मामलों में 'लॉग 10' के निरंतर प्रसार कर सकता है। एक परिवर्तनीय आधार के साथ मापने का प्रयास करें। –

+0

एनबी। 'डबल' के लिए 'फ़्लोटिंग' उदाहरण उपरोक्त 'fooLogBase' की परिभाषित परिभाषा के लिए' लॉगबेस 'को समान रूप से परिभाषित करता है। – dave4420

+1

जब आप एलएलवीएम बैकएंड के साथ संकलित करते हैं तो वे सभी समान रूप से तेज़ होते हैं। – leftaroundabout

उत्तर

22

हमेशा की तरह, कोर को देखें।

फास्ट (1.563s) -

-- note: top level constant, referred to by specialized fooLogBase 

Main.main_lx :: GHC.Types.Double 
Main.main_lx = 
    case GHC.Prim.logDouble# 10.0 of { r -> 
    GHC.Types.D# r 
    } 

Main.main7 :: GHC.Types.Double -> GHC.Types.Double 
Main.main7 = 
    \ (y :: GHC.Types.Double) -> 
    case y of _ { GHC.Types.D# y# -> 
    case GHC.Prim.logDouble# y# of { r0 -> 
    case Main.main_lx of { GHC.Types.D# r -> 
    case GHC.Prim./## r0 r of { r1 -> 
    GHC.Types.D# r1 
    } 
    } 
    } 

धीरे (2.013s)

-- simpler, but recomputes log10 each time 
Main.main7 = 
    \ (y_ahD :: GHC.Types.Double) -> 
    case y_ahD of _ { GHC.Types.D# x_aCD -> 
    case GHC.Prim.logDouble# x_aCD of wild1_aCF { __DEFAULT -> 
    case GHC.Prim.logDouble# 10.0 of wild2_XD9 { __DEFAULT -> 
    case GHC.Prim./## wild1_aCF wild2_XD9 of wild3_aCz { __DEFAULT -> 
    GHC.Types.D# wild3_aCz 
    } 
    } 
    } 
    } 

तेज संस्करण में, log10 एक बार की जाती है और साझा (स्थिर तर्क एक बार ही लागू किया जाता है)। धीमी संस्करण में इसे हर बार फिर से दबाया जाता है।

आप तर्क की इस पंक्ति का पालन करें और भी बेहतर संस्करणों का निर्माण कर सकते हैं:

-- 1.30s 
lx :: Double 
lx = log 10 

log10 :: Double -> Double 
log10 y = log y/lx 

main :: IO() 
main = print . foldl' (+) 0 . map log10 $ [1..1e7] 

और, सरणी संलयन का उपयोग कर, आप compositional शैली के दंड निकाल सकते हैं:

import qualified Data.Vector.Unboxed as V 

lx :: Double 
lx = log 10 

log10 :: Double -> Double 
log10 y = log y/lx 

main :: IO() 
main = print . V.sum . V.map log10 $ V.enumFromN 1 (10^7) 

लागत काटना 3x

$ time ./A 
6.5657059080059275e7 

real 0m0.672s 
user 0m0.000s 
sys  0m0.000s 

जो इसे हाथ से लिखने जैसा अच्छा है। नीचे दिए गए सही ढंग से लिखित संस्करण पर कोई लाभ नहीं है।

lx :: Double 
lx = D# (GHC.Prim.logDouble# 10.0##) 

log10 :: Double -> Double 
log10 (D# y) = D# (case logDouble# y of r -> r /## d#) 
    where 
     D# d# = lx 

main :: IO() 
main = print . V.sum . V.map log10 $ V.enumFromN 1 (10^7) 
+0

यह वास्तव में ghc का गरीब है। एक टिकट वारंट। – augustss

+2

जीएचसी 'लॉगबेस # 10' इतना सस्ता लगता है कि यह इसे बाहर नहीं चलाता है, हालांकि यह वास्तव में यहां मायने रखता है। और लॉगरिदम के लिए कोई विशेष पुनर्लेखन नियम नहीं हैं (इसलिए कोई निरंतर तह नहीं)। –

+7

यह एक बग है। विभिन्न प्राथमिक कार्यों को लगातार फोल्ड या फ्लोट करने की आवश्यकता होती है। – augustss

2

एक और याद किया गया अनुकूलन: निरंतर (लॉग 10) को विभाजित करना पारस्परिक द्वारा गुणा करके बदला जाना चाहिए।

+0

सावधान। वह परिणाम बदल सकता है। –

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