6

我想知道从编程语言/编译器实现的角度来看,使用向负无穷大(Haskell,Ruby)截断而不是向零截断(C,PHP)有哪些好处。

似乎向负无穷大截断是正确的方法,但我还没有找到这种说法的可靠来源,也没有找到这样的决定如何影响编译器的实现。我对可能的编译器优化特别感兴趣,但不是唯一的。

相关来源:

Haskell 中的分部

quotRem 和 divMod 的区别在什么时候有用?

4

3 回答 3

9

这些实际上甚至不是唯一的选择,事实上,通常甚至可能不是最好的。我可以在这里总结一下,但最好只链接到这篇对比截断、下限和欧几里得除法的优秀论文,涵盖理论和一些现实世界的应用,函数 div 和 mod 的欧几里德定义,Raymond T. Boute。

于 2013-09-20T14:23:59.543 回答
5

这是来自 ISO/IEC 10967-1:2012语言独立算术(vl. LIA-1) C.5.1.2.2 附件 C 中的(信息性)基本原理的引用。省略号...由我插入。

... 两种舍入规则是常用的:向负无穷大( quot I ) 舍入,向零舍入。后者在 LIA-1 中未指定,因为当参数具有不同符号时,容易误用。例如,

quot I (-3,2) = -2 向负无穷舍入,在 LIA-1 中指定

div t I (-3,2) = -1 向零舍入,不再由 LIA 的任何部分指定

quot I ... 以及 ... 都满足一个广泛有用的翻译不变量:

   quot I ( x + i * y , y) = quot I ( x , y ) + i    如果y ≠ 0,则不会发生溢出

... quot I是许多数学家首选的整数除法形式。div t I(不再由 LIA 指定)是 Fortran 引入的除法形式。

整数除法经常用于分组。例如,如果要将一系列索引项目划分为n 个项目的组,则将项目i放入 group是很自然的i/n。如果quot I用于整数除法,这可以正常工作。但是,如果使用div t I(不再在 LIA 中指定)并且i可以为负数,则组 0 将获得 2 ⋅ n -1 个项目,而不是所需的n。这种不均匀的负面行为i会导致细微的程序错误,并且是反对使用div t I ...

于 2013-11-13T16:04:58.080 回答
4

整数除法中的不同类型的舍入存在各种权衡。正如杰克麦克阿瑟所说,这不是唯一的。例如,还有四舍五入到最接近的整数。

另一个考虑是整数除法和余数齐头并进。quotient * divisor + remainder = dividend法律成立。所以不同类型的除法舍入会产生不同类型的余数。例如:

  • 除法向零舍入,产生的余数始终与被除数具有相同的符号。例如,在 C 和 Java 中,(-5) % 3 = -2(因为(-5) / 3 = -1, 和(-1) * 3 + (-2) = -5);而5 % (-3) = 2(因为5 / (-3) = -1,和(-1) * (-3) + 2 = 5)。
  • 向负无穷大舍入的除法产生的余数始终与除数具有相同的符号。例如,在 Python 和 Ruby 中,(-5) % 3 = 1(因为(-5) / 3 = -2, 和(-2) * 3 + 1 = -5);而5 % (-3) = -1(因为5 / (-3) = -2,和(-2) * (-3) + (-1) = 5)。
  • 除法四舍五入到最接近的整数,产生一个最小的余数(两个可能的余数)(最接近于零)。

在数学和计算机科学中,具有与除数相同符号的余数通常是最有用的。人们经常需要用一个固定的除数计算余数。例如,x % 2。在余数具有被除数符号的语言中,如 C 和 Java,此表达式的计算结果可能为 -1、0 或 1,具体取决于x. 然而,在余数有除数符号的语言中,比如 Python 和 Ruby,这个表达式只能计算为 0(如果是偶数)或 1(如果是奇数)。这可能更符合预期。

我相信许多处理器架构,包括 x86 架构,都包含一个整数除法指令,该指令向零舍入。因此,在大多数计算机上计算它可能更有效。我不确定是否有整数除法指令向负无穷大舍入。

于 2013-09-23T09:52:26.853 回答