algorithmlogic

How may I prevent this boolean test from running twice?


Consider the pseudo-procedure below:

--beg
    if (condition_a)
        condition_b = !condition_b;
    while (condition_a and condition_b)
        •••Do something that can mutate condition_a and/or condition_b•••
--end

condition_b is an already existing condition that must be toggled (if condition_a is true) before the loop will even start.


condition_a is tested twice which is "unnecessary". I want to remove the "unnecessary" test. [1][2]

I considered the following:

All will lead to multiple setting of condition_b which is also an O(n) test of the condition (worse than my original intention).

What other approach will you suggest?


[1] The use of "unnecessary" is completely subjective and it is actually the premise of this question. I feel like the first test can be avoided and the second test, which is the most significant one, should suffice.

[2] If you disagree with it being unnecessary, please prove your claim of its necessity.


Solution

  • The following would not execute the loop if either condition_a is false, or condition_b is true (before being toggled). As the condition is fully tested before the first iteration of the loop, we can move the loop's condition at the end of the loop's body:

    if (condition_a) {
        if (condition_b) {
            condition_b = false
        } else {
            condition_b = true
            do {
                •••Do something that can mutate condition_a and/or condition_b•••
            } while (condition_a and condition_b)
        }
    }
    

    If you're OK with making an assignment inside a boolean expression, and you can rely on shortcircuit evaluation of &&, you can shorten this to:

    if (condition_a && (condition_b = !condition_b)) { // assignment
        do {
            •••Do something that can mutate condition_a and/or condition_b•••
        } while (condition_a and condition_b)
    }
    

    Avoiding evaluation of condition_a before the loop condition

    If you really wanted to force all to happen within the context of the loop, you'll need to add work to the loop's body, which will affect performance, and the state of condition_b after the loop. For instance:

    while (condition_a && (condition_b = !condition_b)) {
        •••Do something that can mutate condition_a and/or condition_b•••
        condition_b = !condition_b
    }
    

    Note how condition_b is negated at the end of each iteration, so to counter the effect of the negation that happens in the loop-condition. But if condition_a becomes false inside the loop's processing, then condition_b will exit the loop with a negated value. If this is irrelevant to the code that follows, it can be left like that, but if not, you need to guard that change to condition_b:

    while (condition_a && (condition_b = !condition_b)) {
        •••Do something that can mutate condition_a and/or condition_b•••
        if (condition_a) {
            condition_b = !condition_b
        }
    }
    

    This does not look that elegant anymore, and besides the repeated negation of condition_b, it now also evaluates condition_a more than in your original code (once the loop makes at least one iteration).