I have two simple while loops in my program that I feel ought to be math equations, but I\'m struggling to convert them:
float a = someValue;
int b = someOtherVa
Assuming b is positive, abs(c) = floor((abs(a) - b/2) / b). Then, apply sign of a to c.
It can be proved that the following is correct:
c = floor((a+b/2)/b)
a = a - c*b
Note that floor means round down, towards negative infinity: not towards 0. (E.g. floor(-3.1)=-4. The floor()
library functions will do this; just be sure not to just cast to int, which will usually round towards 0 instead.)
Presumably b
is strictly positive, because otherwise neither loop will never terminate: adding b
will not make a
larger and subtracting b
will not make a
smaller. With that assumption, we can prove that the above code works. (And paranoidgeek's code is also almost correct, except that it uses a cast to int instead of floor
.)
Clever way of proving it:
The code adds or subtracts multiples of b
from a
until a
is in [-b/2,b/2)
, which you can view as adding or subtracting integers from a/b
until a/b
is in [-1/2,1/2)
, i.e. until (a/b+1/2)
(call it x
) is in [0,1)
. As you are only changing it by integers, the value of x
does not change mod 1
, i.e. it goes to its remainder mod 1, which is x-floor(x)
. So the effective number of subtractions you make (which is c
) is floor(x)
.
Tedious way of proving it:
At the end of the first loop, the value of c
is the negative of the number of times the loop runs, i.e.:
where x = (a+b/2)/b
, so c is: 0 if x>0 and "ceiling(x)-1" otherwise. If the first loop ran at all, then it was ≤ -b/2 just before the last time the loop was executed, so it is ≤ -b/2+b now, i.e. ≤ b/2. According as whether it is exactly b/2 or not (i.e., whether x
when you started was exactly a non-positive integer or not), the second loop runs exactly 1 time or 0, and c is either ceiling(x) or ceiling(x)-1. So that solves it for the case when the first loop did run.
If the first loop didn't run, then the value of c at the end of the second loop is:
where y = (a-b/2)/b
, so c is: 0 if y<0 and 1+floor(y) otherwise. [And a
now is certainly < b/2 and ≥ -b/2.]
So you can write an expression for 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))
Of course, next you notice that (ceiling(x)-1+(x is integer))
is same as floor(x+1)-1
which is floor(x)
, and that y
is actually x-1
, so (1+floor(y))=floor(x)
, and as for the conditionals:
when x≤0, it cannot be that (y≥0), so c
is just the first term which is floor(x)
,
when 0 < x < 1, neither of the conditions holds, so c
is 0
,
when 1 ≤ x, then only 0≤y, so c is just the second term which is floor(x)
again.
So c = floor(x)
in all cases.
c = (int)((a - (b / 2)) / b + 1);
a -= c * b;
Test case at http://pastebin.com/m1034e639
I think you want something like this:
c = ((int) a + b / 2 * sign(a)) / b
That should match your loops except for certain cases where b is odd because the range from -b/2 to b/2 is smaller than b when b is odd.