Author Topic: Tricky Bools!  (Read 3388 times)

0 Members and 1 Guest are viewing this topic.

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
We've been doing a bit of maintenance with the flags system in FSO, and something interesting came up that made me stop and think.

Specifically, this:

Code: [Select]
#define VM_PADLOCK_UP    (1 << 7)
#define VM_PADLOCK_REAR  (1 << 8)
#define VM_PADLOCK_LEFT  (1 << 9)
#define VM_PADLOCK_RIGHT (1 << 10)
#define VM_PADLOCK_ANY   (VM_PADLOCK_UP|VM_PADLOCK_REAR|VM_PADLOCK_LEFT|VM_PADLOCK_RIGHT)


int Viewer_mode;

// Version A
if (Viewer_mode & ~VM_PADLOCK_ANY) {}

// Version B
if (~Viewer_mode & VM_PADLOCK_ANY) {}

Note versions A and B, which differ only by the location of operator~, which is the bitwise NOT operator (makes all 0's into 1's and 1's into 0's). When placed in an if{} statement, C and C++ regards a non-boolean value (ints, floats, etc.) as TRUE if any bits in the value are 1's (that is, if the value is nonzero, it is TRUE). This little quirk will make things difficult for us as you'll soon see.

Code: [Select]
// Version A
LHS  RHS
00 & ~00 -> 00 & 11 -> 00 -> FALSE  // A right-hand operand of 00 makes no sense for flag checking, so we don't use it
01 & ~00 -> 01 & 11 -> 01 -> TRUE
10 & ~00 -> 10 & 11 -> 10 -> TRUE
11 & ~00 -> 11 & 11 -> 11 -> TRUE

00 & ~01 -> 00 & 10 -> 00 -> FALSE
01 & ~01 -> 01 & 10 -> 00 -> FALSE
10 & ~01 -> 10 & 10 -> 10 -> TRUE
11 & ~01 -> 11 & 10 -> 10 -> TRUE

00 & ~10 -> 00 & 01 -> 00 -> FALSE
01 & ~10 -> 01 & 01 -> 01 -> TRUE
10 & ~10 -> 10 & 01 -> 00 -> FALSE
11 & ~10 -> 11 & 01 -> 01 -> TRUE

00 & ~11 -> 00 & 00 -> 00 -> FALSE
01 & ~11 -> 01 & 00 -> 00 -> FALSE
10 & ~11 -> 10 & 00 -> 00 -> FALSE
11 & ~11 -> 11 & 00 -> 00 -> FALSE

//Version B
LHS  RHS
~00 & 00 -> 11 & 00 -> 00 -> FALSE
~01 & 00 -> 10 & 00 -> 00 -> FALSE
~10 & 00 -> 01 & 00 -> 00 -> FALSE
~11 & 00 -> 00 & 00 -> 00 -> FALSE

~00 & 01 -> 11 & 01 -> 01 -> TRUE
~01 & 01 -> 10 & 01 -> 00 -> FALSE
~10 & 01 -> 01 & 01 -> 01 -> TRUE
~11 & 01 -> 00 & 01 -> 00 -> FALSE
     
~00 & 10 -> 11 & 10 -> 10 -> TRUE
~01 & 10 -> 10 & 10 -> 10 -> TRUE
~10 & 10 -> 01 & 10 -> 00 -> FALSE
~11 & 10 -> 00 & 10 -> 00 -> FALSE
     
~00 & 11 -> 11 & 11 -> 11 -> TRUE
~01 & 11 -> 10 & 11 -> 10 -> TRUE
~10 & 11 -> 01 & 11 -> 01 -> TRUE
~11 & 11 -> 00 & 11 -> 00 -> FALSE


As you can see from the snippet, the two versions are not the same.

Version A seems to check if any of the flags that are 0's in the RHS operand are 1's in the LHS.

Version B seems to check if any flags that are 1's in the RHS operand are 0's in the LHS.

Let's toss in another bit to see if these general rules hold up:

Code: [Select]
// Version A
000 & ~001 -> 000 & 110 -> 000 -> FALSE
001 & ~001 -> 001 & 110 -> 000 -> FALSE
010 & ~001 -> 010 & 110 -> 010 -> TRUE
011 & ~001 -> 011 & 110 -> 010 -> TRUE
100 & ~001 -> 100 & 110 -> 100 -> TRUE
101 & ~001 -> 101 & 110 -> 100 -> TRUE
110 & ~001 -> 110 & 110 -> 110 -> TRUE
111 & ~001 -> 111 & 110 -> 110 -> TRUE

000 & ~010 -> 000 & 101 -> 000 -> FALSE
001 & ~010 -> 001 & 101 -> 001 -> TRUE
010 & ~010 -> 010 & 101 -> 000 -> FALSE
011 & ~010 -> 011 & 101 -> 001 -> TRUE
100 & ~010 -> 100 & 101 -> 100 -> TRUE
101 & ~010 -> 101 & 101 -> 101 -> TRUE
110 & ~010 -> 110 & 101 -> 100 -> TRUE
111 & ~010 -> 111 & 101 -> 101 -> TRUE

000 & ~011 -> 000 & 100 -> 000 -> FALSE
001 & ~011 -> 001 & 100 -> 000 -> FALSE
010 & ~011 -> 010 & 100 -> 000 -> FALSE
011 & ~011 -> 011 & 100 -> 000 -> FALSE
100 & ~011 -> 100 & 100 -> 100 -> TRUE
101 & ~011 -> 101 & 100 -> 100 -> TRUE
110 & ~011 -> 110 & 100 -> 100 -> TRUE
111 & ~011 -> 111 & 100 -> 100 -> TRUE

000 & ~111 -> 000 & 000-> 000 -> FALSE
001 & ~111 -> 001 & 000-> 000 -> FALSE
010 & ~111 -> FALSE
011 & ~111 -> FALSE
100 & ~111 -> FALSE
101 & ~111 -> FALSE
110 & ~111 -> FALSE
111 & ~111 -> FALSE

//Version B
~000 & 001 -> 111 & 001 -> 001 -> TRUE
~001 & 001 -> 110 & 001 -> 000 -> FALSE
~010 & 001 -> 101 & 001 -> 001 -> TRUE
~011 & 001 -> 100 & 001 -> 000 -> FALSE
~100 & 001 -> 011 & 001 -> 001 -> TRUE
~101 & 001 -> 010 & 001 -> 000 -> FALSE
~110 & 001 -> 001 & 001 -> 001 -> TRUE
~111 & 001 -> 000 & 001 -> 000 -> FALSE

~000 & 010 -> 111 & 010 -> 010 -> TRUE
~001 & 010 -> 110 & 010 -> 010 -> TRUE
~010 & 010 -> 101 & 010 -> 000 -> FALSE
~011 & 010 -> 100 & 010 -> 000 -> FALSE
~100 & 010 -> 011 & 010 -> 010 -> TRUE
~101 & 010 -> 010 & 010 -> 010 -> TRUE
~110 & 010 -> 001 & 010 -> 000 -> FALSE
~111 & 010 -> 000 & 010 -> 000 -> FALSE

~000 & 011 -> 111 & 011 -> 011 -> TRUE
~001 & 011 -> 110 & 011 -> 010 -> TRUE
~010 & 011 -> 101 & 011 -> 001 -> TRUE
~011 & 011 -> 100 & 011 -> 000 -> FALSE
~100 & 011 -> 011 & 011 -> 011 -> TRUE
~101 & 011 -> 010 & 011 -> 010 -> TRUE
~110 & 011 -> 001 & 011 -> 001 -> TRUE
~111 & 011 -> 000 & 011 -> 000 -> FALSE

~100 & 111 -> 111 & 111 -> 111 -> TRUE
~001 & 111 -> 110 & 111 -> 110 -> TRUE
~010 & 111 -> 101 & 111 -> 101 -> TRUE
~011 & 111 -> 100 & 111 -> 100 -> TRUE
~100 & 111 -> 011 & 111 -> 011 -> TRUE
~101 & 111 -> 010 & 111 -> 010 -> TRUE
~110 & 111 -> 001 & 111 -> 001 -> TRUE
~111 & 111 -> 000 & 111 -> 000 -> FALSE

Looks like our general rule seems to hold up. Version A makes less sense than version B, because usually when we do a check against flags, we're concerned about the ones that are set rather than the ones that are clear.

"But what if you wanted to check if all bits of the flag where set, or clear?"

Code: [Select]
//Checks if all bits set
(Viewer_mode & VM_PADLOCK_ANY) == VM_PADLOCK_ANY;

// Checks if all bits clear
(Viewer_mode & VM_PADLOCK_ANY) == 0;

« Last Edit: August 17, 2016, 04:11:22 pm by z64555 »
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
As MageKing17 on IRC pointed out, it's preferred to do

Code: [Select]
!(Viewer_mode & VM_PADLOCK_ANY)

when checking if a single bit is clear. This notation also seems to check if all bits are clear.
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline AdmiralRalwood

  • 211
  • The Cthulhu programmer himself!
    • Skype
    • Steam
    • Twitter
when checking if a single bit is clear.
what

I didn't say that
Ph'nglui mglw'nafh Codethulhu GitHub wgah'nagl fhtagn.

schrödinbug (noun) - a bug that manifests itself in running software after a programmer notices that the code should never have worked in the first place.

When you gaze long into BMPMAN, BMPMAN also gazes into you.

"I am one of the best FREDders on Earth" -General Battuta

<Aesaar> literary criticism is vladimir putin

<MageKing17> "There's probably a reason the code is the way it is" is a very dangerous line of thought. :P
<MageKing17> Because the "reason" often turns out to be "nobody noticed it was wrong".
(the very next day)
<MageKing17> this ****ing code did it to me again
<MageKing17> "That doesn't really make sense to me, but I'll assume it was being done for a reason."
<MageKing17> **** ME
<MageKing17> THE REASON IS PEOPLE ARE STUPID
<MageKing17> ESPECIALLY ME

<MageKing17> God damn, I do not understand how this is breaking.
<MageKing17> Everything points to "this should work fine", and yet it's clearly not working.
<MjnMixael> 2 hours later... "God damn, how did this ever work at all?!"
(...)
<MageKing17> so
<MageKing17> more than two hours
<MageKing17> but once again we have reached the inevitable conclusion
<MageKing17> How did this code ever work in the first place!?

<@The_E> Welcome to OpenGL, where standards compliance is optional, and error reporting inconsistent

<MageKing17> It was all working perfectly until I actually tried it on an actual mission.

<IronWorks> I am useful for FSO stuff again. This is a red-letter day!
* z64555 erases "Thursday" and rewrites it in red ink

<MageKing17> TIL the entire homing code is held up by shoestrings and duct tape, basically.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Quote
4:34:08 PM - z64555: checking if a bit is clear. probably will go with !(Viewer_mode & VM_CAMERA_LOCKED)
4:34:21 PM - MageKing17: yes, that's how you should check that
4:34:36 PM - MageKing17: put a "not" in front of a check if a bit is set

Well, that's how I interpreted that. :P
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline AdmiralRalwood

  • 211
  • The Cthulhu programmer himself!
    • Skype
    • Steam
    • Twitter
yes, but the way you wrote it implied that I'd said you should do something else for multiple bits when your question just hadn't been about multiple bits
Ph'nglui mglw'nafh Codethulhu GitHub wgah'nagl fhtagn.

schrödinbug (noun) - a bug that manifests itself in running software after a programmer notices that the code should never have worked in the first place.

When you gaze long into BMPMAN, BMPMAN also gazes into you.

"I am one of the best FREDders on Earth" -General Battuta

<Aesaar> literary criticism is vladimir putin

<MageKing17> "There's probably a reason the code is the way it is" is a very dangerous line of thought. :P
<MageKing17> Because the "reason" often turns out to be "nobody noticed it was wrong".
(the very next day)
<MageKing17> this ****ing code did it to me again
<MageKing17> "That doesn't really make sense to me, but I'll assume it was being done for a reason."
<MageKing17> **** ME
<MageKing17> THE REASON IS PEOPLE ARE STUPID
<MageKing17> ESPECIALLY ME

<MageKing17> God damn, I do not understand how this is breaking.
<MageKing17> Everything points to "this should work fine", and yet it's clearly not working.
<MjnMixael> 2 hours later... "God damn, how did this ever work at all?!"
(...)
<MageKing17> so
<MageKing17> more than two hours
<MageKing17> but once again we have reached the inevitable conclusion
<MageKing17> How did this code ever work in the first place!?

<@The_E> Welcome to OpenGL, where standards compliance is optional, and error reporting inconsistent

<MageKing17> It was all working perfectly until I actually tried it on an actual mission.

<IronWorks> I am useful for FSO stuff again. This is a red-letter day!
* z64555 erases "Thursday" and rewrites it in red ink

<MageKing17> TIL the entire homing code is held up by shoestrings and duct tape, basically.