【问题标题】:In C# integer arithmetic, does a/b/c always equal a/(b*c)?在 C# 整数算术中,a/b/c 是否总是等于 a/(b*c)?
【发布时间】:2013-05-26 03:04:23
【问题描述】:

令 a、b 和 c 为非大正整数。 a/b/c 是否总是等于 a/(b * c) 与 C# 整数算术?对我来说,在 C# 中它看起来像:

int a = 5126, b = 76, c = 14;
int x1 = a / b / c;
int x2 = a / (b * c);

所以我的问题是:x1 == x2 是否适用于所有 a、b 和 c?

【问题讨论】:

  • 这是一道数学题,不是编程题。你能解释一下这个问题的编程特定部分是什么吗?
  • @Oded 在任何有理数的范围内,当然,但这具体指的是整数算术(在 C# 中)。 IMO 使其与编程相关。也许 a/b/c == a/(b*c) 的规则适用于整数运算,也许它只适用于有理数运算。
  • 这是一个关于 C# 的完全合理的问题,而且很容易回答。
  • @Oded 这是一个关于计算机算术以及它的行为是否与纯数学相同的问题。它不应该被关闭。
  • 我对为什么(或是否)的数学证明非常感兴趣,忽略溢出,两者实际上是等价的,但我还没有设法将一个放在一起。跨度>

标签: c# math integer integer-arithmetic


【解决方案1】:

\ 表示整数除法(两个ints 之间的C# / 运算符)并让/ 表示通常的数学除法。那么,如果x,y,z正整数并且我们忽略溢出

(x \ y) \ z
    = floor(floor(x / y) / z)      [1]
    = floor((x / y) / z)           [2]
    = floor(x / (y * z))
    = x \ (y * z)

在哪里

a \ b = floor(a / b)

上面从[1] 行跳转到[2] 行解释如下。假设您有两个整数ab 和一个小数f[0, 1) 范围内。一看就明白了

floor(a / b) = floor((a + f) / b)  [3]

如果在[1] 行中您识别出a = floor(x / y)f = (x / y) - floor(x / y)b = z,则[3] 意味着[1][2] 相等。

您可以将此证明推广到负整数(仍然忽略溢出),但为了简单起见,我将把它留给读者。


关于 overflow 的问题 - 请参阅 Eric Lippert 的回答以获得很好的解释!他还在his blog post 中采取了更严格的方法并回答,如果你觉得我太随意了,你应该研究一下。

【讨论】:

  • 哈,这就是我想要的:)
  • 我喜欢你为此使用 \ 和 /。让事情变得更加清晰。
  • @JustinMorgan 这个符号实际上用在其他一些编程语言中(虽然我现在不记得是哪些)。
  • @TimothyShields VB.net 可以。
  • 我认为该说法是正确的,但您的证明似乎缺少关键步骤。我可能误解了您对第 2 行 => 第 3 行的理由。我解释它的方式是 floor(x / y) - (x / y) 很小,z >= 1 所以取其中的 floor 为 0,我们可以忽略它。这实际上并没有遵循,因为它实际上是 floor() 中的一个加数(即考虑 floor(1/2)floor(1/2 + 1/2))。
【解决方案2】:

我非常喜欢这个问题,所以我把它作为my blog on June 4th, 2013 的主题。谢谢你的好问题!


大案子很容易找到。例如:

a = 1073741823; 
b = 134217727;
c = 134217727;

因为b * c 溢出为负数。

我要补充一点,在 检查算术 中,a / (b * c)(a / b) / c 之间的区别可能是正常运行的程序和崩溃的程序之间的区别。如果bc 的乘积超出了整数的范围,则前者将在检查上下文中崩溃。

对于小的正整数,比如说,小到可以放入一个短整数,应该保持恒等式。


Timothy Shields 刚刚发布了一个证明;我在这里提出一个替代证明。假设这里所有的数字都是非负整数并且没有任何操作溢出。

x / y 的整数除法找到值q 使得q * y + r == x,其中0 <= r < y

所以除法a / (b * c) 找到值q1 使得

q1 * b * c + r1 == a

在哪里0 <= r1 < b * c

除法( a / b ) / c首先找到qt这样的值

qt * b + r3 == a

然后找到值q2 这样

q2 * c + r2 == qt

所以将其替换为qt,我们得到:

q2 * b * c + b * r2 + r3 == a

0 <= r2 < c0 <= r3 < b 的位置。

两个相等的东西彼此相等,所以我们有

q1 * b * c + r1 == q2 * b * c + b * r2 + r3

假设q1 == q2 + x 是某个整数x。将其代入并求解x

q2 * b * c + x * b * c + r1 = q2 * b * c + b * r2 + r3
x  = (b * r2 + r3 - r1) / (b * c)

在哪里

 0 <= r1 < b * c
 0 <= r2 < c
 0 <= r3 < b

x 可以大于零吗?不,我们有不等式:

 b * r2 + r3 - r1 <= b * r2 + r3 <= b * (c - 1) + r3 < b * (c - 1) + b == b * c

所以那个分数的分子总是小于b * c,所以x不能大于零。

x 可以小于零吗?不,通过类似的论点,留给读者。

因此整数x 为零,因此q1 == q2

【讨论】:

  • @JoseRuiSantos 是的,但在这种情况下,x1 x2 操作都会同样崩溃
  • @JoseRuiSantos 这两种情况都不是吗?
  • vc 74 的回答已被删除,因此大多数人无法再看到您引用的示例。
  • 没错,如果bc 为零,x1x2 都会崩溃。对于其他值,x1 表达式更好,因为这将避免x2 所具有的( b * c) 可能的整数溢出。
  • 关于溢出和检查算术的有趣点,谢谢!
【解决方案3】:

计数器示例:INT_MIN / -1 / 2

【讨论】:

  • "设 a、b 和 c 为非大整数。"
  • 这是一个有趣的案例(即 -INT_MIN 是溢出)。谢谢!
【解决方案4】:

为了好玩,我会提供我自己的证明。这也忽略了溢出,不幸的是只处理正面,但我认为证明是干净和清晰的。

我们的目标是展示这一点

floor(floor(x/y)/z) = floor(x/y/z)

其中/ 是正常除法(在整个证明中)。

我们将a/b 的商和余数唯一 表示为a = kb + r(我们的意思是k,r 是唯一的,并且还要注意|r| &lt; |b|)。然后我们有:

(1) floor(x/y) = k => x = ky + r
(2) floor(floor(x/y)/r) = k1 => floor(x/y) = k1*z + r1
(3) floor(x/y/z) = k2 => x/y = k2*z + r2

所以我们的目标只是展示k1 == k2。我们有:

k1*z + r1 = floor(x/y) = k = (x-r)/y (from lines 1 and 2)
=> x/y - r/y = k1*z + r1 => x/y = k1*z + r1 + r/y

因此:

(4) x/y = k1*z + r1 + r/y (from above)
x/y = k2*z + r2 (from line 3)

现在从 (2) 中观察到 r1 是一个整数(因为 k1*z 根据定义是整数)和 r1 &lt; z(也是根据定义)。此外,从(1)我们知道r &lt; y =&gt; r/y &lt; 1。现在考虑来自 (4) 的总和 r1 + r/y。声明是r1 + r/y &lt; z,这从前面的声明中很清楚(因为0 &lt;= r1 &lt; zr1 是一个整数,所以我们有0 &lt;= r1 &lt;= z-1。因此0 &lt;= r1 + r/y &lt; z)。因此r1 + r/y = r2 定义为r2(否则x/y 将有两个 余数,这与余数的定义相矛盾)。因此我们有:

x/y = k1*z + r2
x/y = k2*z + r2

我们得到了我们想要的结论,k1 = k2

上述证明应该适用于否定,除了您需要检查额外案例的几个步骤......但我没有检查。

【讨论】:

    【解决方案5】:

    避免其他人注意到的溢出错误,它们总是匹配的。

    假设a/b=q1,这意味着a=b*q1+r1,其中0&lt;=r1&lt;b
    现在假设a/b/c=q2,这意味着q1=c*q2+r2,其中0&lt;=r2&lt;c
    这意味着a=b(c*q2+r2)+r1=b*c*q2+br2+r1.
    为了a/(b*c)=a/b/c=q2,我们需要有0&lt;=b*r2+r1&lt;b*c
    但是b*r2+r1&lt;b*r2+b=b*(r2+1)&lt;=b*c,根据需要,和两个操作匹配。

    如果bc 为负数,这不起作用,但我也不知道在这种情况下整数除法是如何工作的。

    【讨论】:

      【解决方案6】:

      如果bc 的绝对值低于sqrt(2^31)(约46 300),那么b * c 将永远不会溢出,则这些值将始终匹配。如果b * c 溢出,则可能会在checked 上下文中引发错误,或者您可能会在unchecked 上下文中获得不正确的值。

      【讨论】:

        猜你喜欢
        • 2011-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-13
        • 2011-05-30
        • 2018-04-17
        • 1970-01-01
        相关资源
        最近更新 更多