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 = someOtherValue; int c = 0; while (a <= -b / 2) { c--; a += b; } while (a >= b / 2) { c++; a -= b; }
This code works as-is, but I feel it could be simplified into math equations. The idea here being that this code is taking an offset (someValue) and adjusting a coordinate (c) to minimize the distance from the center of a tile (of size someOtherValue). Any help would be appreciated.
It can be proved that the following is correct:
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
bis strictly positive, because otherwise neither loop will never terminate: addingbwill not makealarger and subtractingbwill not makeasmaller. 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 offloor.)Clever way of proving it: The code adds or subtracts multiples of
bfromauntilais in[-b/2,b/2), which you can view as adding or subtracting integers froma/buntila/bis in[-1/2,1/2), i.e. until(a/b+1/2)(call itx) is in[0,1). As you are only changing it by integers, the value ofxdoes not changemod 1, i.e. it goes to its remainder mod 1, which isx-floor(x). So the effective number of subtractions you make (which isc) isfloor(x).Tedious way of proving it:
At the end of the first loop, the value of
cis 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., whetherxwhen 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. [Andanow is certainly < b/2 and ≥ -b/2.]So you can write an expression for
cas:Of course, next you notice that
(ceiling(x)-1+(x is integer))is same asfloor(x+1)-1which isfloor(x), and thatyis actuallyx-1, so(1+floor(y))=floor(x), and as for the conditionals:when x≤0, it cannot be that (y≥0), so
cis just the first term which isfloor(x),when 0 < x < 1, neither of the conditions holds, so
cis0,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.