div和quot之间的确切差异

Thr*_*eFx 9 haskell operators division

这个问题中div,quot我们提到了两个运营商之间的差异,以及quot运营商比div运营商更有效的事实,而div对我们人类来说更自然.

我的问题是两个运算符的确切实现是什么,并与实现之间的区别有关.此外,我想知道这两者之间的速度差异如何,因为使用Hoogle并浏览源代码并没有帮助我理解.

我想澄清一点,我理解两个运营商之间的一般差异,只对实施或者差异感兴趣.

And*_*ács 9

quot向零舍入,div向负无穷大舍入:

div  (-3) 2 == (-2)
quot (-3) 2 == (-1)
Run Code Online (Sandbox Code Playgroud)

至于开销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#
Run Code Online (Sandbox Code Playgroud)

在最终形式中,两个函数都对它们进行了一些错误处理检查:

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
Run Code Online (Sandbox Code Playgroud)

我还做了一小部分微基准测试,但它应该用大量的盐,因为GHC和LLVM优化紧密的数字代码,就像没有明天一样.我试图阻挠他们,结果似乎是现实:14,67毫秒div13,37毫秒quot.此外,它是带-O2和-fllvm的GHC 7.8.2.这是代码:

{-# 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]
Run Code Online (Sandbox Code Playgroud)