0

Here is my code

int a=2147483647; 
int b= a<<1;
cout<<"a="<<a<<",  b="<<b;

The output I am getting is- a=214783647, b=-2

Binary representation of a is

0111 1111 1111 1111 1111 1111 1111 1111

By shifting it by 1 bit, it will change sign bit and replace LSB with 0. So, I think answer will be -ve and magnitude will be subtracted by 1 i.e -2147483646 But it is giving result as -2 . Please explain.

T.g
  • 169
  • 2
  • 11

3 Answers3

2

[expr.shift]/1 The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. ... if E1 has a signed type and non-negative value, and E1 × 2^E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.

Emphasis mine. Your program exhibits undefined behavior.


Edit: Upon closer consideration, I no longer think it's undefined behavior. 2147483647*2 does fit into unsigned int, "the corresponding unsigned type" of int. Its conversion to int is not undefined, but merely implementation-defined. It's entirely reasonable for an implementation using two's complement to define this conversion so that 2147483647*2 == -2, just reinterpreting the bit pattern, as other answers explained.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • Note that the quoted paragraph is no longer in the C++ Standard. However, this sentence implies the same: http://eel.is/c++draft/expr#pre-4.sentence-1. – Daniel Langr Apr 01 '19 at 14:14
  • Upon closer examination, I no longer think it's undefined behavior. `2147483647*2` does fit into `unsigned int`, "the corresponding unsigned type" of `int`. Its conversion to `int` is not undefined, but merely implementation-defined. It's entirely reasonable for an implementation using two's complement to define this conversion so that `2147483647*2 == -2`, just reinterpreting the bit pattern. – Igor Tandetnik Apr 01 '19 at 14:20
  • @DanielLangr The draft standard you cite [defines left shift thusly](http://eel.is/c++draft/expr.shift#2): "The value of `E1 << E2` is the unique value congruent to `E1×2^E2` modulo `2^N`, where `N` is the width of the type of the result." It so happens that `-2 == 2147483647*2 modulo 2^32`. So I think the draft standard actually expanded the domain of shift operator, and made the original expression well-defined. – Igor Tandetnik Apr 01 '19 at 14:22
  • @IgorTandetnik It did not. 2147483647 * 2 is 4294967294, which modulo 2^32 (N=32 is the width of the `int` type) is still 4294967294. And this number is not in the range of representable values for `int`. – Daniel Langr Apr 01 '19 at 14:34
  • 1
    @DanielLangr I'm not sure I follow. `-2` is the unique value of `int` type that is [congruent](https://en.wikipedia.org/wiki/Modular_arithmetic#Definition_of_congruence_relation) to 4294967294 modulo 2^32, is it not? – Igor Tandetnik Apr 01 '19 at 14:38
  • @IgorTandetnik It's an interesting topic for discussion. The Standard says _the unique value congurent to `E1x2^E2` modulo `2^N`_. However, there is no such unique value, there is an infinite number of such congurent values, for which `((E1< – Daniel Langr Apr 01 '19 at 17:06
  • @DanielLangr I think it's clear that the standard means "unique value of the result type"; not value in the mathematical sense, as obviously there's an infinite number of them and the passage would become meaningless under such an interpretation. Among (the finite number of) values of `int` type, `-2` is in fact the only one congruent to 4294967294 modulo 2^32. – Igor Tandetnik Apr 01 '19 at 20:31
  • @IgorTandetnik I think I figured it out. The definition from http://eel.is/c++draft/expr.shift#2 belongs to the C++ Standard latest draft, which will become C++20. In C++20, two-complement representation of negative integers is required, therefore the left shift of a signed value that "overflows" is defined as well. In C++11, C++14, and C++17, the definition of left shift is different and makes this case undefined. – Daniel Langr Apr 02 '19 at 06:30
  • @IgorTandetnik Anyway, I guess you are right, but I also asked a separate question about this issue to got more opinions. See here if you are interested: https://stackoverflow.com/q/55468807/580083. Of course, your answer is welcomed. – Daniel Langr Apr 02 '19 at 07:31
2

This is because your computer is using 2 complement for the signed value. Unsigned shifted value is 0xFFFFFFFE, which is -2 in 2 complement, not -2147483647.

Shifting is implementation defined in C.

BTW, -2147483647 is 0x80000001 on such CPU.

xryl669
  • 3,376
  • 24
  • 47
1

Well, there is a very long story behind.

Since int is a signed type, it means that the first bit is a sign and the whole system is two-complement.

so x = 0b 1111 1111 1111 1111 1111 1111 1111 0111 is x = -9 and for example x = 0b 1111 1111 1111 1111 1111 1111 1111 1111 is x = -1 and x = 0b 0000 0000 0000 0000 0000 0000 0000 0010 is 2

Learn more about Two complement.

Community
  • 1
  • 1
dzuda11
  • 147
  • 11