0

Consider the following c++ code:

int main()
{
    int a = -3 >> 1;
    int b = -3 / 2;

    cout << "a = " << a << ", b = " << b << endl;
    return 0;
}

When executed, this code give this result:

a = -2, b = -1

I'm a little puzzled, because I thought that these 2 operations produced the same code in the compiled exe, i.e. something like:

shr ax, 1

But it seems that it's not the case (I tested with 2 different compilers). Somebody can explain to me why these operations doesn't produce the same result?

---- EDIT ON the 17.02.2018 ----

Well, I know this is a newbie question, even if I'm not really a beginner in C++

In fact, I understand perfectly what happen in binary when I apply a shift right (i.e. shr or >> operator) on a value. This was not my question.

Rather, my question was about the difference between applying a binary shift on a value or make a division on a value. I expected that the result was the same, because until now I assumed that the compiler replaced a division by 2, or a multiplication by 2, by the appropriate shr/shl instruction during the compilation, as an optimization. Assuming that, the produced binary should be the same for the both instructions, so the result should also be the same.

But it is apparently not the case. For that reason, I would be happy to know what happen under the hood while the compiler compiles these both instruction (analyzing a mnemonic is not really my strong point), what are their differences, and finally, this should let me understand why the result differs in mathematical terms.

As a concrete case, I faced this issue in a source code for a graphical application I tried to make simpler. To facilitate the human reading of the code, I replaced some code like "(widthB - widthA) >> 1" by "(widthB - widthA) / 2". But doing that introduced a bug: several graphic items were no longer centered as expected. From that I noticed that replacing the shifting by a division produced different result if the value to divide was negative, it's the reason of the above question.

I hope this will clear up the situation.

Jean-Milost Reymond
  • 1,833
  • 1
  • 15
  • 36
  • 1
    First of all, dispel from your brain the notion that C++ is defined in terms of CPU operations – Lightness Races in Orbit Feb 16 '18 at 21:26
  • It's not clear to me which part is puzzling you. Do you not see why `-3 >> 1` produces `-2`, or why `-3 / 2` produces `-1`? –  Feb 16 '18 at 21:29
  • 1
    Regarding your edit, there's one very fundamental aspect you've missed, I think: it's not that they produce different results because they get compiled differently. That's backwards. They get compiled differently because they're *supposed to* produce different results (in part because the standard says so, in part because it's dependent on the implementation and the implementation says so). `-3 >> 1` is supposed to produce `-2`, and `-3 / 2` is supposed to produce `-1`, and if they're supposed to produce different results, they clearly require different instructions. –  Feb 18 '18 at 19:07
  • thx hvd, your comment answered my question. That was exactly what I wanted to know. – Jean-Milost Reymond Feb 19 '18 at 16:30

2 Answers2

4

-3 in two's complement system

11111111111111111111111111111101       :BIN

And when shift right

11111111111111111111111111111110       :BIN

That's mean -2 in decimal.

But when you divide two number like -3 / 2 the answer is -1.5 and when cast it to integer it be -1.

amin saffar
  • 1,953
  • 3
  • 22
  • 34
  • How about a one's complement system? Since C++ supports both. For sake of completeness. – Eljay Feb 16 '18 at 22:07
  • @Eljay that's different ~3 -> 11111111111111111111111111111100 and shif right 11111111111111111111111111111110 -> ~1 it's different -3 and ~3 -3 is two's complement ~3 is one's complement – amin saffar Feb 16 '18 at 22:19
0

It has to do with the way signed and unsigned numbers are represented internally, if you give this code a shot you will see that it behaves as expected.

#include <iostream>

using namespace std;

    int main()
    {
        unsigned int a = 3 >> 1;
        unsigned int b = 3 / 2;

        cout << "a = " << a << ", b = " << b << endl;
        return 0;
    }

I suggest looking up "twos compliment"

Mitch
  • 3,342
  • 2
  • 21
  • 31