4

C++03 中的 $5.6/4 声明-“如果两个操作数都是非负数,则余数是非负数;如果不是,则余数的符号是​​实现定义的74)

注释 74 在哪里

根据正在进行的 ISO C 修订工作,整数除法的首选算法遵循 ISO Fortran 标准 ISO/IEC 1539:1991 中定义的规则,其中商始终向零舍入。

C++0x 状态 -

$5.6/4-“对于整数操作数,/运算符产生代数商,其中任何小数部分都被丢弃;如果商 a/b 可以在结果类型中表示,则为79(a/b)*b + a%b ,则等于 a。

注释 79 说

这通常称为向零截断。

所以我有两个问题:

  • 有人可以解释这个“截断为零”的概念吗?

  • 带有负操作数的模数是 C++0x 中定义的行为吗?

4

3 回答 3

6

向零截断意味着通过选择下一个最接近零的整数将实数转换为整数。等效地,您将数字写下来,并忽略小数点后的所有内容,无论该数字是正数还是负数。

考虑 11/4 = 2.75 - 如果将其截断为零,则得到 2。

考虑 -11/4 或 11/-4 = -2.75 - 如果将其截断为零,则得到 -2。

(a/b)*b + a%b == a 对于某些数学运算很重要。如果我们必须使这个等式成立,并且我们也接受整数除法向零截断,那么我们可以推导出运算符的%操作如下:

a == 11, b == 4:
a/b == 2, 2*4 + a%b == 11, therefore a%b == 3.

a == -11, b == 4:
a/b == -2, -2 * 4 + a%b == -11, therefore a%b == -3.

a == 11, b == -4:
a/b == -2, -2 * -4 + a%b == 11, therefore a%b == 3.

a == -11, b == -4:
a/b == 2, 2 * -4 + a%b == -11, therefore a%b == -3.

一开始可能会让人感到困惑,但 C++0x 正在a%b使用方程式定义运算符的行为(a/b)*b + a%b == a。这个等式甚至对负数也成立,所以a%b是为负数定义的。

于 2010-08-29T14:03:03.117 回答
3

a) 考虑(±5)/(±3) -> ±1。在数线上:

  (-5)/3                                     5/3
     5/(-3)                               (-5)/(-3)
      =                                       =
    -1.66 --> -1                       1 <-- 1.66
       v       v                       v       v
-  +  -  -  -  +  -  -  -  +  -  -  -  +  -  -  -  +  -
   |           |           |           |           |
  -2          -1           0           1           2

因此四舍五入趋向于零。

b) 是的。由于a/b现在为所有ab(除了b == 0)和定义(a/b)*b + a%b == a,因此只有 1 个唯一解a%b,所以算子对所有和(除了)%也是良好定义的。abb == 0

于 2010-08-29T14:02:12.170 回答
1

a)“向零截断”仅仅意味着任何小数部分都被删除。截断后的数字始终至少与原始数字一样接近 0,并且通常比原始数字更接近。

这在负数中最为明显,但目标是减少使用/%使用负数时的棘手(因为目前,任何实现都可以根据他们的选择处理它)。-7/4 可以被认为有两种方式:-2 余数为 1,或 -1 余数为 -3。并且有编译器和处理器可以同时处理它。由于-7/4 实际上是-1.75,“向零截断”会给你-1,所以后一种方式是标准的。

b) 这就是它的样子。它一直是半定义的(“实现定义的”),但这看起来像是试图从一开始就定义什么应该是标准的。

于 2010-08-29T14:00:55.960 回答