The most important thing to remember with integer operations is that all division operations are floored (lowered to the nearest integer).
e.g. 5/2 = 2 and 9/10=0
So 9/10*100 = (9/10)*100 = 0*100 = 0
Where as 9*100/10 = (9*100)/10 = 900/10 = 90
The trick is that division breaks commutativity and associativity. All other arithmetic operations (+,-,*,%) behave normally.
Now lets look at your original formula and figure out what is wrong:
Code:
percent += 100/numchunks + ((100/numchunks % numchunks != 0) ? 1 : 0 );
First we need to figure out what it is trying to do. Lets decompose the formula into more basic components. The first part is simply 100/numchunks. If we were in normal math (with at least rational numbers), then percent += 100/numchunks would be sufficient, since 100/numchunks would be the exact percent each chunk is worth.
The second component is attempting to correct for the floor, but it is doing so in a completely nonsensical way. What it is attempting to do is add 1 occasionally to correct for the floor. Imagine the case of numchunks being 3, we want the bar to go 0, 33, 67, 100 instead of 0, 33, 66, 99. As we can see, the points at which we add the ones is definitely dependent on where in the sequence we are providing an obvious reason (besides that it makes no sense) that the correction as given is wrong (it is independent of the progress).
But, let us try to construct a proper correction. We know that between 0 and 100 we will need to add 1 exactly 100%numchunks times, but we need to add them at the correct time. We want to add them each time the fractional part of 100*i/numchunks rolls past .5, but it isn't obvious how we detect this. Since we are looking at fractional parts, we reword the problem in terms of modulus (since we are working with integers), and the problem becomes when does 100*i%numchunks roll past numchunks/2 (exact division here). We can get rid of the exact division using some discrete math triks. We want (all exact math) 100*i%numchunks to roll past (be less than at the previous iteration and greater than or equal to on this iteration) numchunks/2. Since 100*i%numchunks is always an integer (since i is an integer), 100*i%numchunks >= numchunks/2 is equivalent to 100*i%numchunks >= ceil(numchunks/2) is equivalent to 100*i%numchunks >= floor((numchunks+(2-1))/2) or 100*i%numchunks >= floor((numchunks+1)/2).
This is really complicated, and points out why the absolute equation is way preferable to the incremental one, but it is possible. There is a relatively clean form, but it takes a lot more discrete math to prove why it works.
Edit:
So the code I posted missed some cases (iterations being on the same side of half), but new one less than original. I have the working version (in simplified form), but the proof would take me pages to explain.
Oh, just to be clear, since we are in C, division isn't actually floored it is truncated (which makes it a lot more complicated).