0

My actual concern is about this:

The left-shift bit operation is used to multiply values of integer variables quickly. But an integer variable has a defined range of available integers it can store, which is obviously very logical due to the place in bytes which is reserved for it.

Depending on 16-bit or 32-bit system, it preserves either 2 or 4 bytes, which range the available integers from

-32,768 to 32,767 [for signed int] (2 bytes), or 0 to 65,535 [for unsigned int] (2 bytes) on 16-bit

OR

-2,147,483,648 to 2,147,483,647 [for signed int] (4 bytes), or 0 to 4,294,967,295 [for unsigned int] (4 bytes) on 32-bit

My thought is, it should´t be able to multiply the values over the exact half of the maximum integer of the according range.

But what happens then to the values if you proceed the bitwise operation after the value has reached the integer value of the half of the max int value?

Is there an arithmetic pattern which will be applied to it?


One example (in case of 32-bit system):

unsigned int redfox_1 = 2147483647;
unsigned int redfox_2;
redfox_2 = redfox_1 << 1;

/* Which value has redfox_2 now? */

redfox_2 = redfox_1 << 2;

/* Which value has redfox_2 now? */

redfox_2 = redfox_1 << 3;

/* Which value has redfox_2 now? */


/* And so on and on */
/* Is there a arithmetic pattern what will be applied to the value of redfox_2 now?  */

the value stored inside redfox_2 shouldn´t be able to go over 2.147.483.647 because its datatype is unsigned int, which can handle only integers up to 4,294,967,295.

What will happen now with the value of redfox_2?

And Is there a arithmetic pattern in what will happen to the value of redfox_2?

Hope you can understand what i mean.

Thank you very much for any answers.

  • 2
    See details at https://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work – L. Scott Johnson Oct 01 '19 at 12:30
  • 3
    C and C++ are not nanny languages. They do not protect the user from operations that would exceed the range of the data type. Both languages have well-defined semantics for what happens with left-shift operator on unsigned int data types. – Eljay Oct 01 '19 at 12:31
  • @L.ScottJohnson Thanks, but i´ve observed that thread before i posted this question and this thread doesn´t answer my question. – RobertS supports Monica Cellio Oct 01 '19 at 12:32
  • 1
    With this sort of questions, write numbers in hex. The range of `std::uint32_t` is `0x0` to `0xFFFFFFFF`. – MSalters Oct 01 '19 at 12:40
  • @MSalters Ok, thanks for the pro tip. But two Questions: I´ve thought any value would be stored in bytes; how can it exceed the borders of a byte, or in this case of a 4-byte unsigned integer, if i write it in hex? 2. But what if the value is exceeding then the exact half value of the max. possible value of that hex range? – RobertS supports Monica Cellio Oct 01 '19 at 12:49
  • @RobertS: How you write it doesn't matter to how it's stored internally. Hex has the advantage that each hex digit represents exactly 4 bits, so a 32 bit number always can be written with precisely 8 hex digits. – MSalters Oct 01 '19 at 12:51
  • @MSalters I understand that it i can express large numbers in hex more easily, but the question is about what will happen with the stored value in decimal after exceeding the max value possible to store in 32 bits. Based on which 'decimal' arithmetic pattern it will then create the result value(s)?, which of course will lie again in the range 4 bytes/32bits can store. – RobertS supports Monica Cellio Oct 01 '19 at 13:24
  • @RobertS: There **is no stored value in decimal**. Values are stored in binary; decimal is a conversion for I/O. Neither are there really "decimal arithmetic patterns". Math works regardless of the base in which you express it in. – MSalters Oct 01 '19 at 13:31
  • @MSalters i know it is stored in binary code with bits containing either 1 or 0. Maybe the way i want to express myself is a little strange. -> I want to do a left-shift bit operation. Means every bit [assuming a unsigned int variable] is turning one step to the left and the first bit is getting a "0" value. Now this binary code has an equivalent value in decimal. -> Based on which "decimal" pattern behave now the decimal expression(s) of that binary code after exceeding the max value possible to be stored inside that sequence of 4 byte, by using the left-shift bit operation? – RobertS supports Monica Cellio Oct 01 '19 at 13:51

2 Answers2

5

Per the C 2018 standard, 6.5.7 4:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

So, for unsigned integer types, the bits are merely shifted left, and vacated bit positions are filled with zeroes. For signed integer types, the consequences of overflow are not defined by the C standard.

Many C implementations will, in signed shifts, slavishly shift the bits, including shifting value bits into the sign bit, resulting in various positive or negative values that a naïve programmer might not expect. However, since the behavior is not defined by the C standard, a C implementation could also:

  • Clamp the result at INT_MAX or INT_MIN (for int, or the corresponding maxima for the particular type).
  • Shift the value bits without affecting the sign bit.
  • Generate a trap.
  • Transform the program, when the undefined shift is recognized during compilation and optimization, in arbitrary ways, such as removing the entire code path that performs the shift.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Note: this is not an exhaustive list of options. For instance, even if the compiler recognizes only a _possible_ undefined shift depending on arguments, it can use that to deduce legal value ranges. E.g. `INT_MAX << x` tells the compiler that `x==0` so there's no need to calculate `x`. In C, every case of Undefined Behavior has an infinite list of possible outcomes. – MSalters Oct 01 '19 at 12:49
0

If you really want to see the pattern, then just write a program that prints it:

#include <iostream>
#include <ios>
#include <bitset>

int main()
{
    unsigned int redfox = 2147483647;
    std::bitset<32> b;

    for (int i = 0; i < 32; ++i)
    {
        redfox = redfox << 1;
        b = redfox;
        std::cout << std::dec << redfox << ", " << std::hex << redfox << ", " << b << std::endl;
    }
}

This produces:

4294967294, fffffffe, 11111111111111111111111111111110
4294967292, fffffffc, 11111111111111111111111111111100
4294967288, fffffff8, 11111111111111111111111111111000
4294967280, fffffff0, 11111111111111111111111111110000
4294967264, ffffffe0, 11111111111111111111111111100000
4294967232, ffffffc0, 11111111111111111111111111000000
4294967168, ffffff80, 11111111111111111111111110000000
4294967040, ffffff00, 11111111111111111111111100000000
4294966784, fffffe00, 11111111111111111111111000000000
4294966272, fffffc00, 11111111111111111111110000000000
4294965248, fffff800, 11111111111111111111100000000000
4294963200, fffff000, 11111111111111111111000000000000
4294959104, ffffe000, 11111111111111111110000000000000
4294950912, ffffc000, 11111111111111111100000000000000
4294934528, ffff8000, 11111111111111111000000000000000
4294901760, ffff0000, 11111111111111110000000000000000
4294836224, fffe0000, 11111111111111100000000000000000
4294705152, fffc0000, 11111111111111000000000000000000
4294443008, fff80000, 11111111111110000000000000000000
4293918720, fff00000, 11111111111100000000000000000000
4292870144, ffe00000, 11111111111000000000000000000000
4290772992, ffc00000, 11111111110000000000000000000000
4286578688, ff800000, 11111111100000000000000000000000
4278190080, ff000000, 11111111000000000000000000000000
4261412864, fe000000, 11111110000000000000000000000000
4227858432, fc000000, 11111100000000000000000000000000
4160749568, f8000000, 11111000000000000000000000000000
4026531840, f0000000, 11110000000000000000000000000000
3758096384, e0000000, 11100000000000000000000000000000
3221225472, c0000000, 11000000000000000000000000000000
2147483648, 80000000, 10000000000000000000000000000000
         0,        0, 00000000000000000000000000000000
Frodyne
  • 3,547
  • 6
  • 16