可以证明以下说法是正确的:
c = floor((a+b/2)/b)
a = a - c*b
请注意,floor 表示向下舍入,朝向负无穷大:而不是朝向 0。(例如,floor(-3.1)=-4。floor()
库函数将执行此操作;请确保不要只转换为 int,它通常会向 0 舍入。)
想必b
严格为正,因为否则两个循环都不会终止:添加b
不会使a
更大和减去b
不会使a
较小。有了这个假设,我们就可以证明上面的代码是有效的。 (paranoidgeek 的代码也几乎是正确的,除了它使用强制转换为 int 而不是floor
.)
巧妙的证明方法:
该代码添加或减去的倍数b
from a
until a
is in [-b/2,b/2)
,您可以将其视为加法或减法integers from a/b
until a/b
is in [-1/2,1/2)
,即直到(a/b+1/2)
(叫它x
) is in [0,1)
。由于您仅按整数更改它,因此值x
没有改变mod 1
,即它转到它的余数模 1,即x-floor(x)
。因此,您进行的有效减法次数(即c
) is floor(x)
.
乏味的证明方式:
At the end of the first loop, the value of c
is the negative of the number of times the loop runs, i.e.:
- 0 如果:a > -b/2 a+b/2 > 0
- -1 如果:-b/2 ≥ a > -3b/2 0 ≥ a+b/2 > -b 0 ≥ x > -1
- -2 如果:-3b/2≥a > -5b/2 -b ≥ a+b/2 > -2b -1 ≥ x > -2 等等,
where x = (a+b/2)/b
,所以 c 为: 0(如果 x>0),否则为“ceiling(x)-1”。如果第一个循环运行了,那么它在第一个循环之前≤ -b/2上次循环已执行,因此现在 ≤ -b/2+b,即 ≤ b/2。根据是否恰好是 b/2(即,是否x
当你开始时是否恰好是一个非正整数),第二个循环恰好运行 1 次或 0 次,并且 c 是天花板(x)或天花板(x)-1。这样就解决了第一个循环运行时的情况。
如果第一个循环没有运行,则第二个循环结束时 c 的值为:
- 0 如果:a a-b/2
- 1 如果:b/2 ≤ a 0 ≤ a-b/2 0 ≤ y
- 2 如果:3b/2 ≤ a b ≤ a-b/2 1 ≤ y
where y = (a-b/2)/b
,所以 c 为:如果 ya现在肯定是
所以你可以写一个表达式c
as:
x = (a+b/2)/b
y = (a-b/2)/b
c = (x≤0)*(ceiling(x) - 1 + (x is integer))
+(y≥0)*(1 + floor(y))
当然,接下来你会注意到(ceiling(x)-1+(x is integer))
与floor(x+1)-1
这是floor(x)
, 然后y
实际上是x-1
, so (1+floor(y))=floor(x)
,至于条件:
当x≤0时,不可能有(y≥0),所以c
只是第一项floor(x)
,
当 0 c is 0
,
当 1 ≤ x 时,只有 0≤y,所以 c 只是第二项,即floor(x)
再次。
所以c =floor(x)
在所有情况下。