quot
giri verso zero, div
arrotonda verso l'infinito negativo:
div (-3) 2 == (-2)
quot (-3) 2 == (-1)
quanto riguarda l'overhead di div
, quot
ha un corrispondente primitive GHC operation, mentre div
fa some extra work:
quotRemInt :: Int -> Int -> (Int, Int)
(I# x) `quotRemInt` (I# y) = case x `quotRemInt#` y of
(# q, r #) ->
(I# q, I# r)
divModInt# :: Int# -> Int# -> (# Int#, Int# #)
x# `divModInt#` y#
| (x# ># 0#) && (y# <# 0#) = case (x# -# 1#) `quotRemInt#` y# of
(# q, r #) -> (# q -# 1#, r +# y# +# 1# #)
| (x# <# 0#) && (y# ># 0#) = case (x# +# 1#) `quotRemInt#` y# of
(# q, r #) -> (# q -# 1#, r +# y# -# 1# #)
| otherwise = x# `quotRemInt#` y#
Nella finale forme, entrambe le funzioni hanno un po 'di error handling checks on them:
a `quot` b
| b == 0 = divZeroError
| b == (-1) && a == minBound = overflowError -- Note [Order of tests]
-- in GHC.Int
| otherwise = a `quotInt` b
a `div` b
| b == 0 = divZeroError
| b == (-1) && a == minBound = overflowError -- Note [Order of tests]
-- in GHC.Int
| otherwise = a `divInt` b
Ho anche fatto un po 'piccolo di microbenchmarking, ma deve essere assunto con una notevole quantità di sale, perché GHC e LLVM ottimizzare codice numerico stretta via come non c'è domani. Ho cercato di ostacolarli e i risultati sembrano essere realistici: 14,67 ms per div
e 13,37 ms per quot
. Inoltre, è GHC 7.8.2 con -O2 e -fllvm. Ecco il codice:
{-# LANGUAGE BangPatterns #-}
import Criterion.Main
import System.Random
benchOp :: (Int -> Int) -> Int ->()
benchOp f = go 0 0 where
go !i !acc !limit | i < limit = go (i + 1) (f i) limit
| otherwise =()
main = do
limit1 <- randomRIO (1000000, 1000000 :: Int)
limit2 <- randomRIO (1000000, 1000000 :: Int)
n <- randomRIO (100, 100 :: Int)
defaultMain [
bench "div" $ whnf (benchOp (`div` n)) limit1,
bench "quot" $ whnf (benchOp (`quot` n)) limit2]
Ho aggiunto anche un po 'di benchmarking, FYI. –
@ AndrásKovács Grazie per l'ottima risposta! : D – ThreeFx
Come @augustss menziona nella sua risposta alla domanda che hai collegato, la ragione * fondamentale * per la differenza di velocità è che "quot" è ciò che viene solitamente implementato direttamente come istruzione nelle moderne CPU. Quindi, come accennato in seguito, questo è ciò che GHC sceglie come sua operazione primitiva. –