solrize
in #haskell ha fatto una domanda su una versione di questo codice e ho provato altri casi e mi chiedevo cosa stesse succedendo. Sulla mia macchina il codice "veloce" richiede ~ 1 secondo e il codice "lento" richiede ~ 1.3-1.5 (tutto è compilato con ghc -O2
).Perché `logBase 10 x` è più lento di` log x/log 10`, anche se specializzato?
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 speravano che GHC sarebbe in grado di trasformare logBase x y
nella esattamente la stessa cosa di log y/log x
, quando specializzata. Cosa sta succedendo qui e quale sarebbe il modo consigliato di utilizzare logBase
?
ghc potrebbe fare propagazione costante di 'log 10' in alcuni casi. Prova a misurare con una base variabile. –
n.b. L'istanza 'Floating' per' Double' definisce 'logBase' in modo equivalente alla definizione commentata di' fooLogBase' sopra. – dave4420
Sono tutti ugualmente veloci durante la compilazione con il backend LLVM. – leftaroundabout