Search code examples
algorithmlanguage-agnostic

Number distribution


Problem: We have x checkboxes and we want to check y of them evenly.

Example 1: select 50 checkboxes of 100 total.

[-]
[x]
[-]
[x]
...

Example 2: select 33 checkboxes of 100 total.

[-]
[-]
[x]
[-]
[-]
[x]
...

Example 3: select 66 checkboxes of 100 total:

[-]
[x]
[x]
[-]
[x]
[x]
...

But we're having trouble to come up with a formula to check them in code, especially once you go 11/111 or something similar. Anyone has an idea?


Solution

  • Here's a straightforward solution using integer arithmetic:

    void check(char boxes[], int total_count, int check_count)
    {
        int i;
    
        for (i = 0; i < total_count; i++)
            boxes[i] = '-';
    
        for (i = 0; i < check_count; i++)
            boxes[i * total_count / check_count] = 'x';
    }
    

    total_count is the total number of boxes, and check_count is the number of boxes to check.

    First, it sets every box to unchecked. Then, it checks check_count boxes, scaling the counter to the number of boxes.

    Caveat: this is left-biased rather than right-biased like in your examples. That is, it prints x--x-- rather than --x--x. You can turn it around by replacing

            boxes[i * total_count / check_count] = 'x';
    

    with:

            boxes[total_count - (i * total_count / check_count) - 1] = 'x';
    

    Correctness

    Assuming 0 <= check_count <= total_count, and that boxes has space for at least total_count items, we can prove that:

    • No check marks will overlap. i * total_count / check_count increments by at least one on every iteration, because total_count >= check_count.

    • This will not overflow the buffer. The subscript i * total_count / check_count

      • Will be >= 0. i, total_count, and check_count will all be >= 0.

      • Will be < total_count. When n > 0 and d > 0:

        (n * d - 1) / d < n
        

        In other words, if we take n * d / d, and nudge the numerator down, the quotient will go down, too.

        Therefore, (check_count - 1) * total_count / check_count will be less than total_count, with the assumptions made above. A division by zero won't happen because if check_count is 0, the loop in question will have zero iterations.