So knowing multiple people had been tricked by this, I thought hard and got

a=0; b=0;
while((a==0)||(b==0)){...}

We have an answer, but we're stuck with the same problem of knowing whether its right or not. It's clear that you, me and the half dozen of so people who have tried this are too stupid to write this sort of code reliably, so what do we do?

We break the problem down into smaller, more digestible problems, we try to solve one problem at a time, because if you try to solve two, you have to simultaneously think about those two and the interactions of those solutions, we use recipe code that we have used often and understand completely, we use theory to simplify things.

How does that apply here?

The problem statement is "How would you write a while loop to continuously input numbers a and b until both a and b are not 0?"

some 'theory' is that not( A OR B ) === not A AND not B / not( A AND B) === not A OR not B

the problem asks for a while loop:

while(CONDITION){}

that continuously inputs two numbers

while(CONDIDION){
read(a);
read(b);
}

which has a bug because there is a point where we may continue to input numbers after the exit condition is true, so:

while(CONDIDION){
read(a);
if(!CONDITION)break;
read(b);
}

This is already not ideal code because we have code duplication, but I can't see a better way right now, and how are we going to be sure its right when we're done? We could use proofs, but I'm not sure I can use the stuff I've been taught reliably, and I don't think there are many who can. We can use comments to tie the problem statement to the code

// read a and b until not CONDITION
while(CONDIDION){
read(a);
if(!CONDITION)break;
read(b);
}

So, What is CONDITION?

"read a and b until both a and b are not 0"

which is

until (a!=0) && (b!=0)

but there's a not in the way we've expressed things so far so lets get rid of it and use a more familiar pattern of while(!done){do stuff}

// read a and b until (a!=0) && (b!=0)
done= (a!=0) && (b!=0);
while(!done){
read(a);
done=(a!=0) && (b!=0)
if(done)break;
read(b);
done=(a!=0) && (b!=0)
}

which makes one twitch from all the duplication. Perhaps a helper function, and importantly, giving it a good name.

int allNonZero(a,b){ return (a!=0) && (b!=0) ; }
...
// read a and b until (a!=0) && (b!=0)
while(!allNonZero(a,b)){
read(a);
if(allNonZero(a,b))break;
read(b);
}

which is finally something that solves the problem and is clearly correct.

Ok, so I'm not sure about the 'clearly' bit. I see it transforms to my original code, but its a lot longer and has more nots and logic, and so by the definitions I tend to use, it's more difficult to understand and more complicated, and I'm going to go to bed now ( I wrote this all out in ridiculous longhand mostly for my own amusement to see how it would turn out and I'm still not happy with the original problem which converts

if(true)$subjecticon = LJ::trim(lc($form->{'subjecticon'}));

to

my $subjecticon = "";
if ($form->{'subjecticon'} ne "none" &&
$form->{'subjecticon'} ne "") {
$subjecticon = LJ::trim(lc($form->{'subjecticon'}));
}

which makes $subjecticon have values either "" or LJ::trim(lc($form->{'subjecticon'}))

Assuming LJ::trim(lc("")) == "". It would appear to be equivalent to

$subjecticon = LJ::trim(lc($form->{'subjecticon'}));
$subjecticon= "" if $form->{'subjecticon'} eq "none"

)