Understand Bitwise Operators in C++

In summary, this code is doing a bit shift on a number, then adding in the sign bit, then multiplying by the exponent.
  • #1
ChrisVer
Gold Member
3,378
464
Hi guys, I have the following piece of code but I am not sure I understand if I get what it does correctly.

Code:
static const unsigned int m_nBits = 6;
static const unsigned int m_nRanges = 4;
max = SOMENUMBER;
if( max >= (1 << (m_nBits + m_nRanges - 1) )   ){
   doStuff()
}
In fact I'm trying to understand the conditional. It says that if max is greater or equal to (1 <<9) it should do something. right?
1<<9 = (01) << 9 = (1000000000) = 29= 512 right?
(i bolded the binary numbers).

So the if statement will be executed if the value of max is larger or equal to 512?
 
Technology news on Phys.org
  • #2
You have it right!
 
  • Like
Likes jim mcnamara and ChrisVer
  • #3
this looks like one of the worst possible piece of codes in terms of reading... how can one get used and even understand the reason behind those stuff?
 
  • #4
ChrisVer said:
this looks like one of the worst possible piece of codes in terms of reading... how can one get used and even understand the reason behind those stuff?
That's standard C code. Once you work with it for a while, you will improve your fluency.
It's important to be able to express simple stuff like this concisely.
 
  • #5
They should have added comments to this statement to explain the meaning of the m_nRanges and m_nBits to make it more obvious. The naming convention does help some the m_ usually means
member-of the class and the nBits means there's likely an array or structure of some sort named Bits in the class too.

Too many programmers generate write only code that even they can't read after six months.
 
  • #6
Out of context, the meaning of m_nBits and m_nRanges is mysterious. But there may be a context that makes it obvious. The individual bits of SOMENUMBER must have a meaning. That is why it is being compared in terms of bits instead of in terms of the integer 512. There may be documentation somewhere that explains it. Often the explanation is only one place and then it is used without explanation several places. That can't be avoided. The alternative is to explain it over and over again in several places, which is a nightmare to keep up to date.

Isn't there some explanation in the code where m_nBits and m_nRanges are given values? If not, that is bad. But some people put all their documentation in a document and the code itself has very little.
 
Last edited:
  • #7
Put the entire bitshift and additions in their own static const unsigned int. Compiler will remove it for you and it'll make it much easier to read.

Or replace it. Everything in there is constant, so the compiler will precalculate it for you. So it makes no different if you use a bitshift or a multiplier. Once compiled, it'll just be a number.
 
  • #8
In systems with limited memory and slow cpus, bithacks were used often. In fact see:
https://graphics.stanford.edu/~seander/bithacks.html -- You can see what bit twiddling code looks like and what it does.

I did extensive work on 16bit and 8bit machines. We had to do some of this kind of thing to improve performance with ancient compilers. Modern compilers don't need very much of this kind of code for performance. It mostly ends up in OS code now - where objects (usually flags or options) are bit strings.
 
  • #9
Transmitted messages that have discretes and data compacted into bytes are often encoded and decoded with code that is full of this type of bit manipulation. That code is usually so methodical that there hundreds of similar lines. You get used to it and they are not hard to interpret.
 
  • Like
Likes nsaspook
  • #10
data compacted into bytes

Hmmm this sounds more like it... in fact there are comments but I don't quite understand them either, mainly because I don't understand them.
 
  • #11
FactChecker said:
data compacted into bytes
Or data compacted into multibyte memory locations...
ChrisVer said:
Hmmm this sounds more like it... in fact there are comments but I don't quite understand them either, mainly because I don't understand them.
An example of what I mean is how the bits are packed into, say, a 32-bit floating point number. Per the IEE 754 standard for floating point numbers, a single-precision floating point number is divided into three parts:
bit 31 is the sign bit, with 0 for a positive number and 1 for a negative number
bits 23 through 30 hold the exponent, biased by 127 (meaning that the stored value is larger by 127 than the actual exponent of the number)
bits 0 through 22 hold the mantissa, or fractional part of the number.

The float value 4.125 in binary form would be 100.0012, meaning 1 X 2^2 + 0 X 2^1 + 0 X 2^0 + 0 X 2^(-1) + 0 X 2^(-2) + 1 X 2^(-3). In normalized form (a sort of "scientific notation") this would be 1.000012 X 22. Note that in normalized form, the digit to the left of the "binary point" is always 1, so it doesn't need to be stored.
Since this number is positive, bit 31 would be 0.
Bits 23 through 30 would hold the exponent, which would be stored as the binary form of 129 (= 2 + 127).
Bits 0 through 22 would hold the mantissa, the part to the right of the "binary" point. For my example, the bit pattern would be 00001000000000000000000. Notice that this bit pattern agrees with what I showed as the normalized form, except for the leading 1 digit in the normalized form, which is implied.

To extract the various sections of numbers such as these, you need to use the binary AND operator to mask out any bits you don't want, and then you need to shift the resulting bit pattern to the right. To extract bits 23 through 30, you need a bit pattern with those bits set to 1 and all other bits set to 0. A hexadecimal number that does this is 0x07F800000. After ANDing with this mask, the resulting number needs to be shifted right by 23 bits.

Pretty low level stuff...
 
  • Like
Likes Nihar and ChrisVer
  • #12
(Note: information in a message to me should be included in the thread so that others can help)
I don't know what this subject matter is, but apparently there are some x and y errors in m_nRanges = 4 possible ranges and the error values must fit into m_nBits = 6 bits.

From http://acode-browser.usatlas.bnl.go...Interfaces/TrigT1Interfaces/L1METvalue.h#0049
Code:
0046   /** Number of bits in range */
0047   static const unsigned int m_nBits = 6;
0048   /** Number of ET ranges to encode in */
0049   static const unsigned int m_nRanges = 4;
0050   /** Mask to select Ex/Ey bits */
0051   static const unsigned int m_mask = 0x3F;

This code finds the largest absolute X,Y error (line 39) and checks if it can fit into the bits for the error (line 43). If not, it returns an overflow flag and sets METQ to a huge number (line 45).
Otherwise, it calculates the total squared error METQ (line 57) after removing least significant bits (lines 47-56). I don't really understand lines 47-56, but if you know what these ranges and error values are, you should be able to figure out what it is doing with those bits.

From http://acode-browser.usatlas.bnl.go...er/TrigT1/TrigT1Interfaces/src/L1METvalue.cxx
Code:
0034 void LVL1::L1METvalue::calcL1METQ(int Ex, int Ey, int& METQ, bool& Overflow) {
0035
0036   /** Greater of 2 values determines range of bits used */
0037   unsigned int absEx = std::abs(Ex);
0038   unsigned int absEy = std::abs(Ey);
0039   int max = (absEx > absEy ? absEx : absEy);
0040
0041   /** If Ex/Ey overflows the LUT input range, trigger fires all thresholds.
0042       Indicate this with overflow flag and an out of range ETmiss value */
0043   if ( max >= (1<<(m_nBits+m_nRanges-1)) )  {
0044     METQ = 16777216; // 4096**2
0045     Overflow = true;
0046   }
0047   /** Otherwise, emulate precision by checking which ET range we are in and
0048       zeroing bits below that. */
0049   else {
0050     for (unsigned int range = 0; range < m_nRanges; ++range) {
0051       if ( max < (1<<(m_nBits+range)) ) {
0052         absEx &= (m_mask<<range);
0053         absEy &= (m_mask<<range);
0054         break;
0055       }
0056     }
0057     METQ = absEx*absEx + absEy*absEy;
0058     Overflow = false;
0059   }
0060   
0061 }
 
  • #13
This code calculates the value of missing transverse momentum at the L1-trigger decision.

in this code it takes the values of etmiss on the x and y axis. There are some cases when the trigger overflows giving extremely large output to the missing energy values- this is dealt in the first if, where they set a default missing energy value at L1 (~4.1TeV) and flag the trigger as overflow (so the trigger fires!). Here for example, this is done when max(|ex|,|ey|)>512GeV.

In the else, I don't understand what they do either, mainly because I don't have a good intuition of what are those member attributes. That's why I asked whether I understood what happens in the first if-condition and try to understand why someone would use the operators <<, >> in general (so I could try and figure a reason for them to exist- and ultimately get a physical meaning of what this m_* are) instead of the actual numbers they represent...
 
  • #14
ChrisVer said:
This code calculates the value of missing transverse momentum at the L1-trigger decision.

in this code it takes the values of etmiss on the x and y axis. There are some cases when the trigger overflows giving extremely large output to the missing energy values- this is dealt in the first if, where they set a default missing energy value at L1 (~4.1TeV) and flag the trigger as overflow (so the trigger fires!). Here for example, this is done when max(|ex|,|ey|)>512GeV.

In the else, I don't understand what they do either, mainly because I don't have a good intuition of what are those member attributes. That's why I asked whether I understood what happens in the first if-condition and try to understand why someone would use the operators <<, >> in general (so I could try and figure a reason for them to exist- and ultimately get a physical meaning of what this m_* are) instead of the actual numbers they represent...
For some reason the discretes indicating ranges and the ex values are stored in the same variable. Likewise for ey. That's possibly due to them being transmitted together in a compact, encoded data package. So to separate the range information from the ex, ey values, it is necessary to shift the bits left and right to get the data of interest in a good location (also to shift ignored information away). That type of process is easiest to understand using <<, >>, and other bitwise operations.
 
  • Like
Likes Nihar

1. What are bitwise operators in C++?

Bitwise operators in C++ are operators that perform operations on individual bits of binary numbers. They are used to manipulate and extract specific bits from binary data.

2. What are the types of bitwise operators in C++?

There are six types of bitwise operators in C++: AND (&), OR (|), XOR (^), NOT (~), left shift (<<), and right shift (>>).

3. How do bitwise operators work in C++?

Bitwise operators work by performing logical operations on the individual bits of two operands. For example, the AND operator compares each pair of bits and returns 1 if both bits are 1, otherwise it returns 0.

4. What are some practical applications of bitwise operators in C++?

Bitwise operators are commonly used in low-level programming to manipulate binary data and optimize memory usage. They are also used in encryption algorithms, setting and checking bit flags, and performing bit-level operations on hardware registers.

5. Are bitwise operators supported in other programming languages?

Yes, bitwise operators are supported in many other programming languages including Java, C#, Python, and JavaScript. However, they may have slightly different syntax and behavior, so it is important to consult the documentation for each language.

Similar threads

  • Programming and Computer Science
Replies
23
Views
2K
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
31
Views
2K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
19
Views
978
  • Programming and Computer Science
Replies
11
Views
4K
  • Programming and Computer Science
2
Replies
64
Views
5K
  • Programming and Computer Science
Replies
3
Views
6K
  • Programming and Computer Science
Replies
2
Views
3K
Back
Top