【问题标题】:operator modulo change in c++ 11? [duplicate]c++ 11中的运算符模数变化? [复制]
【发布时间】:2012-10-17 12:47:14
【问题描述】:

可能重复:
C++ operator % guarantees

在 c++ 98/03 中

5.6-4

二元 / 运算符产生商,二元 % 运算符 产生第一个表达式除以的余数 第二。如果 / 或 % 的第二个操作数为零,则行为是 不明确的;否则 (a/b)*b + a%b 等于 a。 如果两个操作数 是非负的,那么余数是非负的;如果没有,标志 其余部分由实现定义

在 c++ 11 中:

5.6 -4

二元 / 运算符产生商,二元 % 运算符 产生第一个表达式除以的余数 第二。如果 / 或 % 的第二个操作数为零,则行为是 不明确的。对于整数操作数 / 运算符产生代数 丢弃任何小数部分的商;81 如果商 a/b 是 可以用结果的类型来表示,(a/b)*b + a%b 等于 a。

正如您所见,符号位的实现定义丢失了,它会发生什么?

【问题讨论】:

  • 你想做什么?而这又是如何成为障碍的呢?
  • @AnandVeeramani:有些人只是想避免未定义的(或者,在这种情况下,实现定义的)行为。我很高兴他问这个,当值可能为负时,我避免了模数。
  • C++ 98/03 也有这个脚注:“根据 ISO C 的修订工作,整数除法的首选算法遵循 ISO Fortran 标准 ISO/IEC 1539 中定义的规则: 1991 年,其中商总是向零舍入” C++11 只是将其作为标准的要求(就像 C99 对 C 所做的那样)。删除 % 运算符的实现定义部分就是这样做的结果。
  • @moswald:在这些情况下,您也必须避免使用 / 运算符,因为它的实现定义类似。

标签: c++ c++11 language-lawyer modulo c++03


【解决方案1】:

% 的行为在 C++11 中得到了加强,现在已完全指定(除了除以 0)。

向零截断和标识(a/b)*b + a%b == a 的组合意味着a%b 对于正a 始终为正,对于负a 始终为负。


其数学原因如下:

÷ 为数学除法,/ 为 C++ 除法。

对于任何 a 和 b,我们有 a÷b = a/b + f(其中 f 是小数部分),从标准来看,我们还有 (a/b)*b + a%b == a

已知a/b 会向0 截断,因此我们知道如果a÷b 为正数,则小数部分始终为正数,而负数为a÷b 为负数:

sign(f) == sign(a)*sign(b)

a÷b = a/b + f 可以重新排列为a/b = a÷b - fa可以扩展为(a÷b)*b

(a/b)*b + a%b == a => (a÷b - f)*b+a%b == (a÷b)*b.

现在左侧也可以展开:

(a÷b)*b - f*b + a%b == (a÷b)*b

a%b == f*b

回想一下之前的sign(f)==sign(a)*sign(b),所以:

sign(a%b) == sign(f*b) == sign(a)*sign(b)*sign(b) == sign(a)

【讨论】:

  • @mata: 符号只由a 确定,你搞砸了那里的算术 (-1/2) = -0.5 = 0(截断后),所以 0 + x = - 1,所以 x = -1。
  • @Mankarse:等式始终存在(如 03 标准),唯一新的似乎是所谓的“向零截断”。这个“向零截断”是什么意思?
  • @Gob00st:向零截断意味着除法结果的小数部分被丢弃在结果中,因此 5/4 == 1.25 => 1(丢弃 0.25)和 -7/ 4 == -1.75 => -1(丢弃 -0.75)。
  • 是的,总是有的,不是吗?我的意思是这意味着“a%b 对于正 a 始终为正,对于负 a 始终为负”。 ?而在 03 标准中则不是。
  • @JorgeLuque:从技术上讲,您需要从国家标准机构之一的 ISO 购买 C++ 标准,但 final draft of the standard 是免费提供的,通常与官方标准非常相似。见isocpp.org
【解决方案2】:

算法表示(a/b)*b + a%b = a,如果您记得它是truncate(a/b)*b + a%b = a 使用代数a%b = a - truncate(a/b)*b,则更容易阅读。也就是说,f(a,b) = a - truncate(a/b)*bf(a,b) < 0 的值是多少?

b 是负数还是正数都没有关系。它抵消了自己,因为它出现在分子和分母中。即使truncate(a/b) = 0b 是负数,好吧,当它是0 的乘积时,它也会被抵消。

因此,只有a 的符号决定了f(a,b)a%b 的符号。

【讨论】:

  • 公式始终存在,与 03 标准一样......
  • @Gob00st:不同的是,在 C++03 中,除法的舍入没有完全指定。
猜你喜欢
  • 2012-08-18
  • 1970-01-01
  • 2016-05-18
  • 2013-12-19
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
相关资源
最近更新 更多