Точная разница между 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]