• 0

C++ >>= Bitwise right shift assignment


Question

17 answers to this question

Recommended Posts

  • 0

I'm having hard time understanding what this does, could someone explain this?

 

X = 50

Y = 210

 

X >>= (Y / 210);

 

That assignment divides X by 2.

 

Y / 210 = 1

 

shifting by 1 bit to the right divides by 2 so X = 50 / 2 = 25

 

If you want to find out why that happens you need to know how numbers are represented in binary first. You can find an explanation of the shift operations here.

Link to comment
Share on other sites

  • 0

(base 10) 50 = (binary) 00110010. So shifting 1 bit right results in (binary) 000011001 = (base 10) 25

It's a common operator to use since it reduces code size and increases execution speed since the compiler doesn't have to load floating point and math libraries.

Must be careful though if you need the fractional part of the number for something.

 

Also, shifting 2 bits right = divide by 4, 3 bits, divide by 8, and conversely, shifting 1 bit left would be a multiply by 2, 2 bits = * 4, 3 bits = * 8, et cetera.

Link to comment
Share on other sites

  • 0

Thanks. I was wondering if I could make the operator to multiply resulted 25 by 0.0011 and then return resulted 0.0275 as X making the last line on the code below obsolite?

X = 50
Y = 210

X >>= (Y / 210);
S = X * 0.0011;

?

Link to comment
Share on other sites

  • 0

Thanks. I was wondering if I could make the operator to multiply resulted 25 by 0.0011 and then return resulted 0.0275 as X making the last line on the code below obsolite?

 

Only if X is a float/double, but then the previous shifting could not work properly.

Link to comment
Share on other sites

  • 0

It's a common operator to use since it reduces code size and increases execution speed since the compiler doesn't have to load floating point and math libraries.

That's kinda misleading. Integer division is integer division. It does not cause the compiler to emit floating point instructions. And integer vs floating point math has nothing to do with whether external libraries are linked into the executable. Integer and floating point math is translated pretty much 1:1 to CPU instructions, there's no need for libraries there.

 

Furthermore, any compiler worth its salt is able to replace integer divisions with powers of 2 with the corresponding bit shifts automatically. Note that it might not necessarily do it because depending on CPU architectures, a bit shift is not necessarily faster than integer division.

 

See http://stackoverflow.com/a/6359099/154766.

  • Like 2
Link to comment
Share on other sites

  • 0

Or, since you're doing * 0.0011, multiply everything by 10000 so you lose the decimal point and don't require floats, and format the output accordingly.

Link to comment
Share on other sites

  • 0

That's kinda misleading. Integer division is integer division. It does not cause the compiler to emit floating point instructions. And integer vs floating point math has nothing to do with whether external libraries are linked into the executable. Integer and floating point math is translated pretty much 1:1 to CPU instructions, there's no need for libraries there.

Furthermore, any compiler worth its salt is able to replace integer divisions with powers of 2 with the corresponding bit shifts automatically. Note that it might not necessarily do it because depending on CPU architectures, a bit shift is not necessarily faster than integer division.

See http://stackoverflow.com/a/6359099/154766.

Yes, I made a blanket statement which may not have been applicable to all situations.

 

Architectures which natively support division won't suffer from this as the compiler should use what hardware is available.

Link to comment
Share on other sites

  • 0

Good point about architectures that don't have hardware division. I tend to forget just how much ARM sucks.

 

I can't speak for you, but when I learned the ARM ISA it included the SDIV and UDIV instructions. Below are quotes from the ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition.

 

A8.6.155 SDIV

Signed Divide divides a 32-bit signed integer register value by a 32-bit signed integer register value, and writes the result to the destination register. The condition code flags are not affected.

 

A8.6.237 UDIV

Unsigned Divide divides a 32-bit unsigned integer register value by a 32-bit unsigned integer register value, and writes the result to the destination register. The condition code flags are not affected.

Link to comment
Share on other sites

  • 0

I can't speak for you, but when I learned the ARM ISA it included the SDIV and UDIV instructions. Below are quotes from the ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition.

Yes but from what I've read most embedded devices like smartphones don't use these instructions sets yet. See (http://wanderingcoder.net/2010/07/19/ought-arm/):

 

?But!? you may say, having finally returned victorious from the ARM manual ?You?re wrong! There is an ARM division instruction, even two! Here, sdiv and udiv!? Sorry to rain on your parade, but these instructions are only available in the ARMv7-R and ARMv7-M profiles (real-time and embedded, respectively ? think motor microcontrollers and wristwatches), not in ARMv7-A which is the profile that the iOS devices that have ARMv7 do support. Sorry!

 

Link to comment
Share on other sites

  • 0

Asik, you caught me. Most of the ARM development I do is embedded (where I have to either write assembly or write my C code to take advantage of the hardware). Therefore I work primarily with ARMv7-M and sometimes ARMv7-R series processors. I know that ARMv7-A is much more commonly used in smartphones and non-embedded devices (like my Samsung Chromebook), but since I have never had to worry about writing assembly for them, I made the (apparently false) assumption that they used a superset of the ARMv7-M ISA. Although the post you linked to reads very much like a rant, it does have a lot of good information. Thanks for the link!

Link to comment
Share on other sites

  • 0

I read somewhere bitwise shift are useful for some math operation like:

R = (X * Y) MOD M

where X, Y & M values are still in max bit-ness the CPU registers can handle, hence also the R;

but the (X*Y) results were definitively larger than the CPU registers limit.

Link to comment
Share on other sites

  • 0

My favorite trick (Which isn't needed at all, but the logic behind it is useful) is this
 
A = B * (1 / C)
 
So instead of dividing B by C, you divide 1 by C to get the reciprocal, then multiply B by that. Divisions are often much sower in hardware than multiplications, so this can provide a nice speed up (Which is why compilers now do it automatically, hence why it's not needed at all)

Link to comment
Share on other sites

  • 0

I've been trying to find a simple way to do this but haven't found anything. Anyone have any ideas?

 

X is random int between 1-99.

            if (X >= 99)
            {
                Z = Z * 0.198;
            }
            else if (X >= 98)
            {
                Z = Z * 0.197;
            }
            
            ...

            else if (X >= 3)
            {
                Z = Z * 0.102;
            }
 
           else if (X >= 2)
            {
                Z = Z * 0.101;
            }
            else
            {
                Z = Z * 0.1;
            }

Bitwise right shift assignment would work if only I could do something like this with it:

 

>>= (Y / 210) * 0.1;

Link to comment
Share on other sites

  • 0

Can't you replace those dozens of if-elses with:

Z *= 0.1 + ((X - 1) / 100.0)

? I mean clearly that's the mathematical formula you're trying to hardcode for a specific range.

 
Not sure what X >>= (Y / 210) * 0.1 is supposed to be, the right-hand side expression is a double so you can't right-shift by that, and what is Y?
Link to comment
Share on other sites

  • 0

 

Can't you replace those dozens of if-elses with:

Z *= 0.1 + ((X - 1) / 100.0)

? I mean clearly that's the mathematical formula you're trying to hardcode for a specific range.

 
Not sure what X >>= (Y / 210) * 0.1 is supposed to be, the right-hand side expression is a double so you can't right-shift by that, and what is Y?

 

 

Forget that, I was thinking about that for so long I didn't know what I was thinking anymore.

 

I would need to do some calculations based on what year it is. For example I have years 1990-2013, I would have to check what year it is and then multiply X by 0.1-0.23. I haven't found any other way than if else, I wonder if anyone have any simpler ideas to avoid long if else statement.

 

int year = 1990...2013

Int64 X = 20

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.