什么时候使用quotRem和divMod的区别有用?
当我们需要判断一个整数是奇数还是偶数时,rem和mod的差异就显现出来了。在上面的例子中,我们定义了一个函数buggyOdd来判断一个整数是否为奇数,使用了rem运算符。但是,当输入为负数时,结果却不符合预期。为了得到正确的结果,我们可以使用mod运算符来定义一个新的函数odd。
然而,我们也可以通过将odd函数定义为x `rem` 2 /= 0来避免这些问题。需要注意的是,对于y > 0,x mod y始终返回大于等于0的值,而x rem y则返回0或与x具有相同符号的值。
因此,当我们需要判断奇偶性时,我们可以选择使用rem或mod运算符,但需要根据具体情况选择合适的运算符来避免出现错误的结果。
当使用GHC在x86上时,对Int类型使用quotRem会编译为单个机器指令,而divMod则需要更多的工作。所以如果你在一个速度关键的部分工作,并且只处理正数,那么应该选择quotRem。
在解决SPOJ primes问题时,使用rem而不是mod,让我的测试文件在32位Ubuntu上的Haskell平台2011下运行时间从5.533秒缩短到了4.758秒。这意味着更快的版本在这个平台下快了16%。
我认为这并不正确。如果你在整个程序中只有一个mod操作,并且看到了相同的改进会怎么样呢?
我说过,当我将primes代码中的mod调用改为rem时,我看到了20%的加速。这不是一个理论上的评论。这是对一个事件的描述。我只改变了一件事情(虽然有多个地方),但我看到了20%的加速。似乎20%的加速确实发生了。
啊,我以为"更快的版本"是指rem,而不是你修改后的程序。(不确定为什么我认为你不会直接说rem,如果你是这个意思的话...)
在许多架构上,包括x86,在除以非常量时,使用截断向零除法比向负无穷大取整更快,但是当除以许多常量值时,特别是2的幂,截断向零要快得多(例如一条指令对应三条指令)。我认为对速度敏感的代码很可能有更多的"快速"除法而不是慢速的除法。
出现这个问题的原因是,当处理正数且在速度关键的部分时,使用quotRem比divMod更快。解决方法是使用quotRem代替divMod来提高速度。另外,使用rem而不是mod可以在除以非常量时提高速度。在除以许多常量值时,特别是2的幂时,使用rem更快。
在许多编程语言中,都存在一个"mod"或"%"运算符,用于在除法运算后截断取余数,例如C、C++和Java等语言。Haskell的quot和rem函数被设计成模拟这种行为,可能是为了与某些C程序的输出兼容。Haskell的div和mod函数以及Python的/和%运算符则遵循数学家(至少是数论学家)的约定,总是向下截断除法(而不是向0截断),以使余数始终为非负数。
实际上,C99和C++11确实规定了截断至0的定义,但较早的版本将其定义为实现定义,因此"与C兼容"不太可能(或者至少是不好的)是其他语言或程序选择向0截断的原因。
对于Python而言,当被除数大于0且除数小于0时,取余结果是负数。这如何符合你所说的"数学家的约定"?
这个问题的出现原因是希望找到一种方法,使得quotRem和divMod函数满足以下性质:对于任意x和y,如果(q,r) = divMod x y,那么x = q*y + r。然而,通过运行一个例子,我们可以看到这并不能解释为什么mod的符号要与第二个操作数一致。无论如何,这个问题的解决方法目前还不清楚。