Точная разница между div и quot

на этой вопрос здесь, так что различия между двумя операторами div и quot упоминаются, а также тот факт, что quot оператор более эффективен, чем div оператора, в то время как div более естественно для нас, людей, чтобы использовать.

мой вопрос заключается в том, каковы точные реализации двух операторов и связаны с тем, в чем разница между реализациями. Также я хочу знать, как разница в скорости между ними два приходит, как с помощью Hoogle и просмотр источников не помог мне в моих поисках понимания.

Я хочу уточнить, что я понимаю общую разницу между двумя операторами и интересуюсь только реализациями или, скорее, различиями.

1 ответов


quot патронов к нулю, div раунды к отрицательной бесконечности:

div  (-3) 2 == (-2)
quot (-3) 2 == (-1)

как издержки div, quot соответствует примитивная операция GHC, а div тут дополнительная работа:

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#

в своих окончательных формах обе функции имеют некоторые проверка обработки ошибок на них:

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

Я также сделал очень маленький кусочек microbenchmarking, но его следует принять с изрядным количеством соли, потому что GHC и LLVM оптимизируют жесткий цифровой код, как будто завтра нет. Я попытался помешать им, и результаты кажутся реалистичными:14,67 МС на div и 13,37 МС на quot. Кроме того, это GHC 7.8.2 с-O2 и-fllvm. Вот код:

{-# 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]