为什么在C#中,-2 % 360会得到-2而不是358?

6

Microsoft Mathematics和Google的计算器在对-2% 360进行计算时输出358,但C#和Windows计算器都输出-2...哪一个是正确的答案?


5
请看http://en.wikipedia.org/wiki/Remainder中的“编程语言中的商和余数”。 - Pascal Cuoq
1
简单的定义是“除法的余数”。按照这个定义,-2可能更正确——毕竟,当你将-2除以360时,余数为2(或-2,取决于你如何看待它),而绝对不会得到358。但对于计算应用程序来说,358通常是一个更有用的答案,这就是为什么一些语言选择返回它的原因。 - Joe White
6个回答

12

根据C#规范,对于整数,C#编译器正在做正确的事情:

x % y的结果是由x - (x/y) * y产生的值。

请注意,(x/y)总是朝零舍入。详情请参阅

有关二进制和十进制浮点数如何计算余数的详细信息,请参见规范的7.8.3节。

这是否是你认为的"正确答案"取决于你如何看待余数运算。余数必须满足以下等式:

dividend = quotient * divisor + remainder

我清楚地说,-2 % 360 等于 -2。为什么呢?首先问问自己商是多少。360 在 -2 中能够整除吗?显然不能!360 无法整除 -2。如果商是零,那么余数必须为 -2 才能满足等式。如果说 360 在 -2 中整除共计 -1 次,并余下 358,这听起来很奇怪,不是吗?


这完全取决于你的观点。从一个角度来看,你的最后一段是没问题的。另一个角度会认为 a % b 的结果在范围 0..b-1 内。所以我不确定你能否认为 358旅 是错的。我认为最重要的是结果由语言规范定义。是的,我在看你,C++! - David Heffernan
一个问题:C#编译器显然正在做正确的事情(因为它将正确的操作数推送到评估堆栈并调用rem)。尽管如此,编译器仍然依赖于rem IL指令的定义行为来确保正确的C#行为。您是否认为这是一个“实现”细节,因为如果CLR团队决定rem的行为不同(虽然不会发生但请配合一下),那么C#团队将不得不请求一个特殊的rem2 IL指令?还是这就是重点:语言被设计为遵循IL规范? - dlev
3
每个基本的 C# 操作整数的 IL 指令都是有意而为之。1999 年时,IL 设计人员和 C# 设计人员常常同时在同一个房间里讨论设计。C# 是为了匹配 IL 而设计的吗?还是 IL 被设计成与 C# 匹配?谁知道呢?这已经被时间的迷雾所掩盖。 - Eric Lippert

7

哪个答案是正确的?

两个答案都是正确的。只是返回的值在惯例上有所不同。


3

我在以下网址找到了一篇非常易懂的解释:http://mathforum.org/library/drmath/view/52343.html

There are different ways of thinking about remainders when you deal 
with negative numbers, and he is probably confusing two of them. The 
mod function is defined as the amount by which a number exceeds the 
largest integer multiple of the divisor that is not greater than that 
number. In this case, -340 lies between -360 and -300, so -360 is the 
greatest multiple LESS than -340; we subtract 60 * -6 = -360 from -340 
and get 20:

-420 -360 -300 -240 -180 -120  -60   0   60   120  180  240  300  360
--+----+----+----+----+----+----+----+----+----+----+----+----+----+--
       | |                                                    |  |
   -360| |-340                                             300|  |340
       |=|                                                    |==|
        20                                                     40

Working with a positive number like 340, the multiple we subtract is 
smaller in absolute value, giving us 40; but with negative numbers, we 
subtract a number with a LARGER absolute value, so that the mod 
function returns a positive value. This is not always what people 
expect, but it is consistent.

If you want the remainder, ignoring the sign, you have to take the 
absolute value before using the mod function.

医生彼得森,数学论坛http://mathforum.org/dr.math/


3

两者都可以看作是模运算,详见维基百科。


0
在我看来,-2更容易理解和编码。如果你将-2除以360,答案是0余数-2...就像将2除以360一样,余数是0余数2。考虑到358也是-2模360的余数并不那么自然。

1
我已经从事编程工作20年了,发现当我执行N%M时,我总是希望结果在0..M-1范围内,因此-2%360应该是358。 话虽如此,大多数语言并不是这样工作的,所以我编写了一个特殊的模数函数来进行补偿。为什么这是自然的呢?嗯,在一个圆中有360度。如果您想确保所有角度都在0..360范围内,您自然会编写“angle%360”。但很快您就会意识到它对负角度无效。 - Qwertie

0

来自wikipedia

如果余数不为零,则有两种可能的余数选择,一种是负数,另一种是正数,并且商也有两种可能的选择。通常,在数论中,总是选择正余数,但编程语言根据a和n的符号以及语言的不同而选择。然而,Pascal和Algol68对于负除数不满足这些条件,一些编程语言(例如C89)甚至不定义结果,如果n或a中任意一个为负数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接