L_M
L_M

Reputation: 41

How do the conversions between signed, unsigned and float types work?

The compiler I use is g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4.

I compile my programs with the following command:

g++ -std=c++11 -pedantic -Wall program.cpp

The program no. 1.:

#include <iostream>
using namespace std;

int main() {
  unsigned int b;
  b = -54;
  cout << b << endl;
  return 0;
}

The program prints 4294967242 and this is the value I expected, because this is the case when we assign an out-of-range value to a variable of unsigned type, so the result is the remainder of a modulo division.

The program no. 2.:

#include <iostream>
using namespace std;

int main() {
  unsigned int b;
  b = 54.1234;
  cout << b << endl;
  return 0;
}

The program prints 54, and this is also OK, because the stored value is the part before the decimal point, and the franctional part is truncated.

The program no. 3.:

#include <iostream>
using namespace std;

int main() {
  unsigned int b;
  b = -54.1234;
  cout << b << endl;
  return 0;
}

Here during compilation I get the warning "overflow in implicit constant conversion".

And the program prints 0. Why is it so? I thought that it will do the truncation of the fractional part (as in program 2) and then store the result of the modulo division (as in program 1).

But if I write program no. 4.:

program no. 4.

#include <iostream>
using namespace std;

int main() {
  unsigned int b;
  float k = -54.1234;
  b = k;
  cout << b << endl;
  return 0;
}

then I get no warning, and I get the result (expected by me) 4294967242, which is the result of the modulo division.

I would be grateful if somebody can explain it to me.

Why doesn't the program no. 3 behave like program no. 4? Why don't I get a warning when compiling program no. 1, but I get one when compiling program no. 3.?

Upvotes: 2

Views: 52

Answers (2)

Jerry Coffin
Jerry Coffin

Reputation: 490653

According to the standard (§[conv.fpint]).

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

So, your -54.1234 is truncated to -54. Since that can't be represented in an unsigned, you get undefined behavior.

Upvotes: 4

gnasher729
gnasher729

Reputation: 52622

When converting floating point numbers to integers, C and C++ round floating point numbers towards zero. The rounded result must then be representable in the destination type.

As a result, for 32 bit unsigned int the conversion is guaranteed to give the correct result if -1 < x < 2^32. For smaller numbers there are no guarantees. Since numbers between -1 and 0 must be rounded to zero, and numbers -1 and smaller have no requirements, it wouldn't be surprising if the compiler checks whether x < 0 and gives a result of 0 in that case. (The compiler might check whether x < 1 and give a result of 0; this handles very small positive numbers as well).

Upvotes: 1

Related Questions