我的程序中有两个简单的while循环,我觉得应该是数学方程式,但我很难转换它们:
float a = someValue;
int b = someOtherValue;
int c = 0;
while (a <= -b / 2) {
c--;
a += b;
}
while (a >= b / 2) {
c++;
a -= b;
}
此代码按原样运行,但我觉得它可以简化为数学方程式。这里的想法是这个代码采用偏移量(someValue)并调整坐标(c)以最小化距瓷砖中心的距离(大小为someOtherValue)。任何帮助将不胜感激。
答案 0 :(得分:36)
可以证明以下是正确的:
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
中添加或减去a
的倍数,直到a
[-b/2,b/2)
为a/b
,您可以在a/b
中查看添加或减去整数 {1}} [-1/2,1/2)
在(a/b+1/2)
之前,x
(称之为[0,1)
)在x
之前{1}}。由于您只是按整数更改它,mod 1
的值不会更改x-floor(x)
,即它会转到余数mod 1 ,即c
。因此,您所做的有效减法次数(floor(x)
)为c
。
证明它的繁琐方式:
<子>
在第一个循环结束时,x = (a+b/2)/b
的值是循环运行次数的负数,即:
其中x
,所以c是:如果x> 0则为0,否则为“ceiling(x)-1”。如果第一个循环完全运行,那么在最后一次循环执行之前它是≤-b / 2,所以现在≤-b / 2 + b,即≤b/ 2 。根据它是否正好是b / 2(即,当你开始时是y = (a-b/2)/b
是否是一个非正整数),第二个循环恰好运行1次或0,c是天花板( x)或ceiling(x)-1。所以这解决了第一个循环运行时的情况。
如果第一个循环没有运行,那么第二个循环结束时c的值为:
其中a
,所以c为:如果y <0则为0,否则为1 + floor(y)。 [而c
现在肯定是&lt; b / 2且≥-b / 2.]
因此,您可以将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
实际上是(1+floor(y))=floor(x)
,所以{{1和条件:
当x≤0时,它不能是(y≥0),因此c
只是floor(x)
的第一项,
当0 < x&lt; 1,这两个条件都不成立,因此c
为0
,
当1≤x时,则只有0≤y,所以c再次是floor(x)
的第二项。
所以c = floor(x)
。
答案 1 :(得分:2)
c = (int)((a - (b / 2)) / b + 1);
a -= c * b;
的测试用例
答案 2 :(得分:1)
我想你想要这样的东西:
c = ((int) a + b / 2 * sign(a)) / b
那应该匹配你的循环,除了某些情况,其中b是奇数,因为当b是奇数时,-b / 2到b / 2的范围小于b。
答案 3 :(得分:0)
假设b为正,则abs(c)= floor((abs(a)-b / 2)/ b)。然后,将a的符号应用于c。