div和quot之间的确切区别 [英] Exact difference between div and quot
问题描述
在这里这个问题上,两个运营商之间的差异<$ c提及$ c> div 和 quot
以及 quot
运算符比 div
运算符更高效,而 div
对我们人类来说更自然。
我的问题是两个操作符的确切实现是什么,并且链接到实现之间的区别是什么。另外,我想知道这两者之间的速度差异是如何发生的,例如使用 Hoogle 和浏览消息来源并没有帮助我寻求理解。
我想澄清一下,我理解两个操作符之间的一般区别,只对实现感兴趣,差异。
div(-3)2 ==(-2)
quot(-3)2 ==(-1)
div
, quot
有相应的原始GHC操作,而 div
does 一些额外的工作:
quotRemInt :: Int - > Int - > (#q,r#) - >的情况下(Int,Int)
(I#x)`RemInt`(I#y)= case x`quotRemInt#
(I#q,I#r)
divModInt#:: Int# - > Int# - > (#Int#,Int##)
x#`divModInt#`y#
| (x#>#0#)&& (#q,r#) - >(#y#<#0#)= case(x# - #1#)`quotRemInt#`y# (#q - #1#,r +#y#+#1##)
| (x#<#0#)&& (#q,r#) - >的情况下(y#>#0#)= case(x#+#1#)`quotRemInt#`y# (#q - #1#,r +#y# - #1##)
|否则= x#`quotRemInt#`y#
在它们的最终形式中,这两个函数都有一个错误处理检查:
a`quot` b
| b == 0 = divZeroError
| b ==(-1)&& a == minBound = overflowError - 注意[测试顺序]
- 在GHC.Int
|否则= a`quotInt` b
a`div` b
| b == 0 = divZeroError
| b ==(-1)&& a == minBound = overflowError - 注意[测试顺序]
- 在GHC.Int
|否则= a`divInt` b
我也做了很少的微基准,但它应该是因为GHC和LLVM优化紧密的数字代码,就像没有明天一样。我试图挫败他们,结果似乎是现实的: 14,67 ms div 和 13.37 ms strong> for 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 |我< limit = go(i + 1)(f i)限制
|否则=()
main = do
limit1< - randomRIO(1000000,1000000 :: Int)
limit2< - randomRIO(1000000,1000000 :: Int)
n < - randomRIO(100,100 :: Int)
defaultMain [
benchdiv$ whnf(benchOp(`div` n))limit1,
benchquot $ whnf(benchOp(`quot` n))limit2]
In this question here on SO the differences between the two operators div
and quot
are mentioned as well as the fact that the quot
operator is more efficient than the div
operator, whereas div
is more natural for us humans to use.
My question is what the exact implementations of the two operators are and linked to that what the difference between implementations is. Also I want to know how the speed difference between those two comes to be, as using Hoogle and browsing the sources did not help me in my quest to understanding.
I want to clarify that I understand the general difference between the two operators and only am interested in the implementations or rather the differences.
quot
rounds towards zero, div
rounds towards negative infinity:
div (-3) 2 == (-2)
quot (-3) 2 == (-1)
As to the overhead of div
, quot
has a corresponding primitive GHC operation, while div
does 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#
In their final forms, both functions have some 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
I also did a very small bit of microbenchmarking, but it should be taken with a hefty amount of salt, because GHC and LLVM optimize tight numeric code away like there's no tomorrow. I tried to thwart them, and the results seem to be realistic: 14,67 ms for div
and 13,37 ms for quot
. Also, it's GHC 7.8.2 with -O2 and -fllvm. Here's the code:
{-# 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]
这篇关于div和quot之间的确切区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!