Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Weird signed/unsigned integer division in C++

int main(int argc, char *argv[]) {
    int i = -100;
    unsigned u = 10;

    cout << "i = " << i << endl;

    i *= u;
    cout << "i*10 = " << i << endl;

    i /= u;
    cout << "i = " << i << endl;

    return 0;
}

I wouldn’t be asking the question here, if the output hadn’t been:

i = -100
i*10 = -1000
i = 429496629
  • In the case of multiplication, unsigned is implicitely converted to signed. So far, so good.
  • However, In the case of division, signed is implicitely converted to unsigned, unsigned division performed; then converted back to signed.

Does anyone have any idea why this is happening? Because it does not make any sence to me.

P.S. The expected behavior is achieved by explicit typecast: i /= (int) u;

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

In the case of multiplication, unsigned is implicitely converted to signed.

That is false. When an int and unsigned int are used as operands to either the * operator or the / operator , the int argument is converted to unsigned int.

This is spelled out in section 8p11 of the C++17 standard :

Many binary operators that expect operands of arithmetic or
enumeration type cause conversions and yield result types in a similar
way. The purpose is to yield a common type, which is also the type of
the result. This pattern is called the usual arithmetic conversions,
which are defined as follows:

  • (11.1) If either operand is of scoped enumeration type (10.2), no conversions are performed; if the other operand does not have the same
    type, the expression is ill-formed.
  • (11.2) If either operand is of type long double, the other shall be converted to long double.
  • (11.3) Otherwise, if either operand is double, the other shall be converted to double.
  • (11.4) Otherwise, if either operand is float, the other shall be converted to float.
  • (11.5) Otherwise, the integral promotions (7.6) shall be performed on both operands. Then the following rules shall be applied to the
    promoted operands:

    • (11.5.1) If both operands have the same type, no further conversion is needed.
    • (11.5.2) Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser
      integer conversion rank shall be converted to the type of the operand
      with greater rank.
    • (11.5.3) Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other
      operand, the operand with signed integer type shall be converted to
      the type of the operand with unsigned integer type.
    • (11.5.4) Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with
      unsigned integer type, the operand with unsigned integer type shall be
      converted to the type of the operand with signed integer type.
    • (11.5.5) Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with
      signed integer type.

The section in bold above is what applies here.

So in this expression:

i *= u;

Which is equivalent to this:

i = i * u;

The value of i which is -100 is converted to an unsigned value which (assuming a 32 bit int) is 4294967196. The multiplication causes wraparound which results in 4294966296. This value is then converted to int when assigned back to i. This conversion is implementation defined although most implementations will simply reinterpret the representation as int which will result in the value -1000.

Then in this expression:

i /= u;

Which is the same as this:

i = i / u;

The same conversion happens as before, so the int value -1000 is converted to the unsigned value 4294966296. The result of the division is then 429496629. This value is in the range of an int, so it is assigned directly back to i without conversion.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading