我想知道从编程语言/编译器实现的角度来看,使用向负无穷大(Haskell,Ruby)截断而不是向零截断(C,PHP)有哪些好处。
似乎向负无穷大截断是正确的方法,但我还没有找到这种说法的可靠来源,也没有找到这样的决定如何影响编译器的实现。我对可能的编译器优化特别感兴趣,但不是唯一的。
相关来源:
我想知道从编程语言/编译器实现的角度来看,使用向负无穷大(Haskell,Ruby)截断而不是向零截断(C,PHP)有哪些好处。
似乎向负无穷大截断是正确的方法,但我还没有找到这种说法的可靠来源,也没有找到这样的决定如何影响编译器的实现。我对可能的编译器优化特别感兴趣,但不是唯一的。
相关来源:
这些实际上甚至不是唯一的选择,事实上,通常甚至可能不是最好的。我可以在这里总结一下,但最好只链接到这篇对比截断、下限和欧几里得除法的优秀论文,涵盖理论和一些现实世界的应用,函数 div 和 mod 的欧几里德定义,Raymond T. Boute。
这是来自 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 ...
整数除法中的不同类型的舍入存在各种权衡。正如杰克麦克阿瑟所说,这不是唯一的。例如,还有四舍五入到最接近的整数。
另一个考虑是整数除法和余数齐头并进。quotient * divisor + remainder = dividend
法律成立。所以不同类型的除法舍入会产生不同类型的余数。例如:
(-5) % 3 = -2
(因为(-5) / 3 = -1
, 和(-1) * 3 + (-2) = -5
);而5 % (-3) = 2
(因为5 / (-3) = -1
,和(-1) * (-3) + 2 = 5
)。(-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 架构,都包含一个整数除法指令,该指令向零舍入。因此,在大多数计算机上计算它可能更有效。我不确定是否有整数除法指令向负无穷大舍入。