solrize
w # haskell zadał pytanie dotyczące jednej wersji tego kodu i próbowałem innych przypadków i zastanawiałem się, co się dzieje. Na moim komputerze "szybki" kod zajmuje ~ 1 sekundę, a "wolny" kod ~ 1.3-1.5 (wszystko jest skompilowane z ghc -O2
).Dlaczego "logBase 10 x" wolniej niż "log x/log 10", nawet gdy jest wyspecjalizowany?
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 nadzieję, że GHC byłby w stanie włączyć logBase x y
się dokładnie tak samo jak log y/log x
, gdy wyspecjalizowane. Co się tutaj dzieje i jaki byłby zalecany sposób używania logBase
?
ghc może w niektórych przypadkach robić stałą propagację 'log 10'. Spróbuj mierzyć zmienną bazą. –
n.b. Instancja 'Floating' dla' Double' definiuje 'logBase' równoważnie do skomentowanej definicji' fooLogBase' powyżej. – dave4420
Wszystkie są równie szybkie, gdy kompilujesz z backendem LLVM. – leftaroundabout