为什么X % 0
是无效表达式?
我一直认为X % 0
应该等于X。既然你不能除以零,那么答案自然应该是余数X(剩下的所有东西),但为什么这个表达式是无效的呢?
为什么X % 0
是无效表达式?
我一直认为X % 0
应该等于X。既然你不能除以零,那么答案自然应该是余数X(剩下的所有东西),但为什么这个表达式是无效的呢?
C++标准(2003年版)第5.6/4节中指出:
[...] 如果除法或取模运算符的第二个操作数为零,则其行为是未定义的; [...]
也就是说,下面这些表达式会导致未定义行为(UB):
X / 0; //UB
X % 0; //UB
还要注意,-5 % 2
并不等于-(5 % 2)
(正如Petar在他的答案评论中所暗示的那样)。这是由实现定义的。规范说明了(§5.6/4):
[...] 如果两个操作数都是非负的,则余数为非负的;如果不是,则余数的符号由实现定义。
a
和b
,a/b + a%b
不再是实现定义,而是等于a
(否则行为未定义)。这个变化发生在C99和C++11中(也许在C++03中已经有了TR1,我不知道)。如果您能将问题标记为C,那就太好了,因为在这方面它们是相同的(这是一个C问题,重复了这个问题)。 - mafsoINT_MIN%-1
被定义,尽管在许多平台上会引发异常。在C11中,只有当x / y
被定义时,才定义x%y
,并且从来不能安全地假定INT_MIN%-1
会被评估。 - mafso这个答案不适用于数学家。为了提供动机(代价是数学精度),本答案试图解释原理。
数学家:请点击此处。
程序员:请记住,除以0
是未定义的
。因此,依赖除法的 mod
也是 未定义的
。
这表示正数X
和D
的除法;它由整数部分和小数部分组成:
(X / D) = integer + fraction
= floor(X / D) + (X % D) / D
重新排列后,你得到:
(X % D) = D * (X / D) - D * floor(X / D)
将 D
替换为 0
:
(X % 0) = 0 * (X / 0) - 0 * floor(X / 0)
由于除以 0
是 undefined
,因此:
(X % 0) = 0 * undefined - 0 * floor(undefined)
= undefined - undefined
= undefined
(X % 0) = 0 * (w/e)
,然后称之为零呢? - Yatharth Agarwal0 * (w/e)
并不总是等于 0。如果 w/e
是一个实数(包括整数),那么它就是 0。如果不是,普通的乘法就无法给出答案,即答案是未定义的。 - Dominick PastoreX % D
的定义是一个数字 0 <= R < D
,使得存在一个 Q
满足下列条件:
X = D*Q + R
因此,如果D = 0
,则不存在这样的数字(因为0 <= R < 0
)
x < 0
,那么 x % y
的符号是由实现定义的。在我的系统上,-5 % 2
恰好是 -1。 - mu is too shortD = 0
时,X = D*Q + R
对于 任何 Q
都有效,其中 X = R
是 OP 所需的。但是,无法满足 0 <= R < 0
。您的答案似乎暗示了相反的情况,尽管我可能只是读错了。 - hammar-5 % 2
实际上并不等于-(5 % 2)
。这是有实现定义的。规范中说,如果两个操作数都是非负数,则余数为非负数;否则,余数的符号由实现定义。 - Nawaz我认为因为要获得X % 0
的余数,你需要先计算X / 0
,这将产生无穷大,而尝试计算无穷大的余数并不是真正可能的。
然而,与您的想法相符的最佳解决方案是这样做:
REMAIN = Y ? X % Y : X
另一个可能在概念上易于理解这个问题的方法:
暂且不考虑参数符号的问题,a % b
可以很容易地重写为 a - ((a / b) * b)
。如果 b
为零,则表达式 a / b
未定义,因此在这种情况下整个表达式也必须是未定义的。
最终,模运算实际上是一种除法运算,因此如果 a / b
未定义,则合理地期望 a % b
也是未定义的。
X % Y
的结果位于整数范围[ 0, Y )
内。而X % 0
的结果必须大于或等于零,并且小于零。
x%y
的符号是实现定义的。在我的系统上,-5%2
恰好为-1。 - mu is too short10 - 3 = 7
7 - 3 = 4
4 - 3 = 1
所以
10 / 3 = 3
10 % 3 = 1
将1除以0:
1 / 0
1 - 0 = 1
1 - 0 = 1
1 - 0 = 1
...
所以
1 / 0 = Infinity (technically even infinity is too small, but it's easy to classify it as that)
1 % 0 = NaN
如果没有阻止它的东西,CPU将继续执行此操作,直到超载并返回完全随机的结果。因此,在CPU级别上有一条指令,如果除数为0,则返回 NaN
或 Infinity
(取决于您的平台)。
这永远不会结束,所以余数未定义(对于计算机来说是 NaN
)。
1 / 0 = Infinity
和1 % 0 = NaN
时,整数没有inf
和NaN
值。它们仅适用于IEEE754标准的浮点数。1.0 / 0.0
是inf
,但1 / 0
(如果两个都是整数)会导致崩溃。 - Nikita DemodovInfinity
和NaN
,如果是整数,则无法将其转换为正确的类型,但概念相同。 - Anonymous你可以通过使用浮点数的身份mod(a,b)来避免(A%B)的"除以0"情况,其中float(B)=b=0.0是未定义的,或者在任何两个实现之间定义不同,以避免逻辑错误(硬崩溃)而产生算术错误...
通过计算mod([a*b],[b])==b*(a-floor(a))
而不是
计算mod([a],[b])
其中[a*b]==您的x轴,随时间变化 [b] == 秋千曲线的最大值(永远不会达到)== 秋千函数的一阶导数
ans = Y ? X % Y : X
%
符号的数学定义,而在那里,他们解释了为什么错误不够清晰明了。 - xanatos