Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 把while循环变成数学方程?_C++_C_Algorithm_Math - Fatal编程技术网

C++ 把while循环变成数学方程?

C++ 把while循环变成数学方程?,c++,c,algorithm,math,C++,C,Algorithm,Math,我的程序中有两个简单的while循环,我觉得应该是数学方程,但我正在努力转换它们: float a = someValue; int b = someOtherValue; int c = 0; while (a <= -b / 2) { c--; a += b; } while (a >= b / 2) { c++; a -= b; } float a=someValue; int b=其他值; int c=0; 而(a=b/2){ C++; a

我的程序中有两个简单的while循环,我觉得应该是数学方程,但我正在努力转换它们:

float a = someValue;
int b = someOtherValue;
int c = 0;

while (a <= -b / 2) {
    c--;
    a += b;
}
while (a >= b / 2) {
    c++;
    a -= b;
}
float a=someValue;
int b=其他值;
int c=0;
而(a=b/2){
C++;
a-=b;
}

这段代码按原样工作,但我觉得它可以简化为数学方程。这里的想法是,该代码采用偏移量(someValue)并调整坐标(c),以最小化与瓷砖中心的距离(大小为someOtherValue)。任何帮助都将不胜感激。

我想您需要这样的帮助:

c = ((int) a + b / 2 * sign(a)) / b

这应该与你的循环相匹配,除非某些情况下b是奇数,因为当b是奇数时,从-b/2到b/2的范围比b小。

假设b是正的,abs(c)=地板((abs(a)-b/2)/b)。然后,将a的符号应用于c

c = (int)((a - (b / 2)) / b + 1);
a -= c * b;

测试用例在

可以证明以下内容是正确的:

c = floor((a+b/2)/b)
a = a - c*b
请注意,floor表示向下取整,朝向负无穷大:而不是朝向0。(例如,floor(-3.1)=-4.
floor()
库函数将执行此操作;请确保不要仅强制转换为int,int通常会向0取整。)

大概
b
是严格正的,因为否则两个循环都不会终止:添加
b
不会使
a
变大,减去
b
不会使
a
变小。有了这个假设,我们可以证明上面的代码是有效的。(偏执狂极客的代码也几乎正确,只是它使用了转换为int而不是
floor

证明它的聪明方法: 代码从
a
添加或减去
b
的倍数,直到
a
位于
[-b/2,b/2)
,您可以将其视为从
a/b
添加或减去整数,直到
a/b
位于
[-1/2,1/2)
,即直到
(a/b+1/2)
(称之为
x
)位于
[0,1)
。由于您仅通过整数对其进行更改,
x
的值不会更改
mod 1
,即它转到其余数mod 1,即
x-floor(x)
。因此您进行的有效减法次数(即
c
)为
floor(x)

证明这一点的繁琐方法

在第一个循环结束时,
c
的值是循环运行次数的负数,即:

  • 如果:a>-b/2 a+b/2>0,则为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等
其中
x=(a+b/2)/b
,因此如果x>0,则c为:0,否则为“天花板(x)-1”。如果第一个循环运行,则它为≤ -b/2就在上次执行循环之前,因此≤ -b/2+b现在,即。≤ b/2.根据它是否正好是b/2(即,当您开始时,
x
是否正好是一个非正整数),第二个循环正好运行1次或0次,c是上限(x)或上限(x)-1。因此,对于第一个循环确实运行的情况,这就解决了它

如果第一个循环未运行,则第二个循环末尾的c值为:

  • 0如果:a
  • 1如果:b/2≤a<3b/20≤a-b/2
  • 2如果:3b/2≤a<5b/2 b≤a-b/2<2b-1≤y<2等

其中
y=(a-b/2)/b
,所以c是:0,如果y“sin”,而不是“sign”,但是是的,你想要一个sin波函数。我认为Dave真正的意思是sign(),由:int sign(x){return x>0?1:x<0?-1:0;}定义不正确:对于一个简单的例子,假设a=b=10,那么两个循环都不会运行(所以c=0)但是这个答案会说c=1。史莱瓦萨:那不是真的。如果a=b=10,那么a>=b/2,那么后面的循环将运行一次,c=1。哦,对不起,我没有想清楚。对于a=b=10,这表示c=((int)10+5)/10,实际上是1.5:-)但是如果a和b是整数,那么“/”意味着整数除法,那么对于正a,它是地板(a+b/2)/b、 所以正确,对于负a,它是ceil(a-b/2)/b=地板((a+b/2)/b),b |(a-b/2)除外。使用floor而不是通过将小数部分转换为整数来删除小数部分,这使它适用于负值。回答很好。它工作得很完美,尽管我需要读几遍才能完全理解它。我的荣幸:)事实上,我想它可能会简单一点……我只是按照我第一次计算出来的方式写的。如果有什么是错误的fusing,请指出它,我再看一看。你的版本肯定不等同于OP的代码,因为OP的代码可能包含无限循环,而你的代码总是终止。你的分析是错误的,因为它假设浮点数遵守代数规则。它们不遵守。特别是
a+b==a
但是
b!=0
。尝试
a=0x10000000
b=1
。然后假设IEEE float,
a-b==a
。我同意你的答案与OP可能想要的答案一致,但重要的是实现浮点运算通常不能满足你的要求。你的代码版本,而不是翻译版本,更多的是一个错误修正。很好的洞察——看到这可以浓缩成一个简单的公式。有人能告诉我这两个循环是怎么做的吗?我一辈子都想不出它能比一个分开的“b”的瓷砖好:…|…|…|…|…|…瓷砖编号,第0个瓷砖的中心是0(从-b/2到b/2)。这段代码想找出哪个磁贴“a”在其中。第一个循环移动a,直到它不在中间磁贴的左边,第二个循环移动a,直到它不在中间。@litb:这可能会有帮助:想想你将如何实现“%”(余数)(例如,模数为正数),只使用加法和减法,而不使用内置的%或除法。
x = (a+b/2)/b
y = (a-b/2)/b
c = (x≤0)*(ceiling(x) - 1 + (x is integer))
   +(y≥0)*(1 + floor(y))