在正整数a/(b*c)
上使用整数除法时,将a/b/c
替换为a,b,c
是否安全,或者我是否有丢失信息的风险?
我做了一些随机测试但找不到a/(b*c) != a/b/c
的例子,所以我很确定它是安全的,但不太确定如何证明它。
谢谢。
答案 0 :(得分:11)
作为数学表达式,⌊a/(bc)⌋
和⌊⌊a/b⌋/c⌋
只要b
非零且c
为正整数(特别是正整数a
) ,b
,c
)。这些东西的标准参考是由Graham,Knuth和Patashnik撰写的令人愉快的书 Concrete Mathematics:计算机科学基础。其中,第3章主要是关于地板和天花板,这在第71页证明是一个更为一般的结果的一部分:
在上面的3.10中,您可以定义x = a/b
(数学,即实际划分)和f(x) = x/c
(再次精确划分),并将其插入左侧⌊f(x)⌋ = ⌊f(⌊x⌋)⌋
的结果中(在验证f
上的条件在此处保留时)以使LHS上的⌊a/(bc)⌋
等于RHS上的⌊⌊a/b⌋/c⌋
。
如果我们不想依赖书中的参考,我们可以直接使用他们的方法证明⌊a/(bc)⌋ = ⌊⌊a/b⌋/c⌋
。请注意,对于x = a/b
(实数),我们要尝试证明的是⌊x/c⌋ = ⌊⌊x⌋/c⌋
。所以:
x
是一个整数,则无需证明,x = ⌊x⌋
。⌊x⌋ < x
,所以⌊x⌋/c < x/c
表示⌊⌊x⌋/c⌋ ≤ ⌊x/c⌋
。 (我们希望表明它是平等的。)假设为了相互矛盾,⌊⌊x⌋/c⌋ < ⌊x/c⌋
那么⌊x⌋ < y ≤ x
和y/c = ⌊x/c⌋
必须有一个数字y。 (当我们将数字从⌊x⌋
增加到x
并考虑按c
划分时,我们必须在某个地方达到确切的值⌊x/c⌋
。)但这意味着{{1} }是y = c*⌊x/c⌋
和⌊x⌋
之间的整数,这是一个矛盾!这证明了结果。
x
打印(使用32位整数),
#include <stdio.h>
int main() {
unsigned int a = 142857;
unsigned int b = 65537;
unsigned int c = 65537;
printf("a/(b*c) = %d\n", a/(b*c));
printf("a/b/c = %d\n", a/b/c);
}
(我使用无符号整数作为它们的溢出行为是well-defined,所以上面的输出是有保证的。对于有符号整数,溢出是未定义的行为,所以程序实际上可以打印(或做)任何,只会强调结果可能不同的点。)
但是如果你没有溢出,那么你在程序中得到的值等于它们的数学值(也就是说,代码中的a/(b*c) = 1
a/b/c = 0
等于数学值{{1} },并且代码中的a/(b*c)
等于数学值⌊a/(bc)⌋
),我们已经证明它们是相等的。因此,当a/b/c
足够小而不会溢出时,⌊⌊a/b⌋/c⌋
可以安全地替换代码中的a/(b*c)
。
答案 1 :(得分:2)
只要你跟踪你的除数和红利,就可以重新排序嵌套的地板分割。
#python3.x
x // m // n = x // (m * n)
#python2.x
x / m / n = x / (m * n)
证明(在python3.x中没有LaTeX :()很糟糕:
Let k = x // m
then k - 1 < x / m <= k
and (k - 1) / n < x / (m * n) <= k / n
In addition, (x // m) // n = k // n
and because x // m <= x / m and (x // m) // n <= (x / m) // n
k // n <= x // (m * n)
Now, if k // n < x // (m * n)
then k / n < x / (m * n)
and this contradicts the above statement that x / (m * n) <= k / n
so if k // n <= x // (m * n) and k // n !< x // (m * n)
then k // n = x // (m * n)
and (x // m) // n = x // (m * n)
https://en.wikipedia.org/wiki/Floor_and_ceiling_functions#Nested_divisions
答案 2 :(得分:2)
虽然b*c
可能会溢出(在C中)原始计算,但a/b/c
无法溢出,因此我们不需要担心前置替换的溢出{{ 1}}。不过,我们需要另外担心。
让a/(b*c) -> a/b/c
。对于某些x = a/b/c
,我会a/b == x*c + y
,而y < c
则为a == (x*c + y)*b + z
。
因此,z < b
。 a == x*b*c + y*b + z
最多为y*b + z
,因此b*c-1
和x*b*c <= a <= (x+1)*b*c
。
因此,a/(b*c) == x
和a/b/c == a/(b*c)
替换a/(b*c)
是安全的。