【问题标题】:Advantages of using truncation towards minus infinity vs towards zero使用截断朝向负无穷与朝向零的优点
【发布时间】:2013-09-25 21:32:45
【问题描述】:

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

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

相关来源:

Division in Haskell

When is the difference between quotRem and divMod useful?

【问题讨论】:

    标签: haskell compiler-construction truncate


    【解决方案1】:

    这些实际上甚至不是唯一的选择,事实上,通常甚至可能不是最好的。我可以在这里总结一下,但最好只链接到这篇出色的论文,该论文对比了截断、下限和欧几里得除法,涵盖了理论和一些实际应用,The Euclidean Definition of Functions div and mod, Raymond T. Boute。

    【讨论】:

    • 论文的结论更具体一点。它指出,向负无穷大的截断(称为 F 定义)是唯一与 E 定义可比的(在理想的性质上)。
    • 对于正除数的截断和这个“欧几里得”定义是相同的(也就是说,divmod 是相同的)。差异仅适用于负除数。
    【解决方案2】:

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

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

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

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

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

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

    ... quotI 是许多数学家首选的整数除法形式。 divtI(LIA不再指定)是Fortran引入的除法形式。

    整数除法经常用于分组。例如,如果要将一系列索引项划分为 n 个项的组,则将项i 放入组i/n 是很自然的。如果 quotI 用于整数除法,这很好用。但是,如果使用 divtI(LIA 中不再指定),并且 i 可以为负数,则第 0 组将得到 2 ⋅ n-1 项而不是所需的n。负面i 的这种不均匀行为可能会导致细微的程序错误,并且是反对使用 divtI 的强烈理由 ...

    【讨论】:

    • 我想不出任何时候我发现舍入为零,也没有相关的余数函数,有用。此外,我能想到的唯一代码 a==(a/b)*b + a%b 保证有用的是试图解决除法使用向零舍入这一事实的代码。另一个向负无穷取整获胜的地方,顺便说一句:计算诸如三个数字的四舍五入之类的东西。 (a+b+c+1)/3 表达式在平均值为正或使用舍入负无穷除法时效果很好。如何用四舍五入做等价的?
    • @supercat:需要一遍遍地重复 :-)
    【解决方案3】:

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

    另一个考虑是整数除法和余数齐头并进。 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 架构,都包含一个整数除法指令,该指令向零舍入。因此,在大多数计算机上计算它可能更有效。我不确定是否有整数除法指令向负无穷大舍入。

    【讨论】:

    • 没有一个 x86 指令用于将整数除以任意除数,该除数向负无穷大舍入,但有一个指令用于将有符号数除以 2 的幂(算术右移)。此外,对于许多常数除数,可以使用四个快速指令(加载、乘法、加法、移位)执行向负无穷大舍入的除法,但向零舍入会使事情变得更慢和更复杂。
    • 显然只是一个小错字,但你写5 % (-3) = 1的地方我想你的意思是5 % (-3) = -1(在python中测试)
    • @JoshuaPerrett:已修复
    猜你喜欢
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多