在this问题中,我们提到了两个运算符div
和quot
之间的差异,以及quot
运算符比div
运算符,而div
对我们人类来说更自然。
我的问题是两个运算符的确切实现是什么,并且与实现之间的差异有关。此外,我想知道这两者之间的速度差异如何,因为使用Hoogle并浏览源代码并没有帮助我理解。
我想澄清一点,我理解两个运营商之间的一般差异,只对实施感兴趣,而不是对差异感兴趣。
答案 0 :(得分:9)
quot
朝零,div
轮向负无穷大:
div (-3) 2 == (-2)
quot (-3) 2 == (-1)
至于div
的开销,quot
有primitive GHC operation,而div
有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#
在最终形式中,两个函数都有一些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
我也做了一小部分微基准测试,但它应该用大量的盐,因为GHC和LLVM优化紧密的数字代码,就像没有明天一样。我试图阻止他们,结果似乎是现实的:div
的 14,67 ms 和quot
的 13,37 ms 。此外,它的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]