Narrowing Conversion from Unsigned to Double

narrowing conversion from unsigned to double

Why is this a narrowing conversion?

Because the definition includes (with my emphasis):

C++11 8.5.4/7 A narrowing conversion is an implicit conversion
[...] from an integer type [...] to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type.

u is not a constant expression, so it's a narrowing conversion whether or not all possible values of the source type might be representable in the target type.

Isn't every unsigned perfectly representable as a double?

That's implementation defined. In the common case of 32-bit unsigned and double with a 52-bit mantissa, that is the case; but some implementations have larger unsigned and/or smaller double representations, so code that depends on that assumption is not portable.

Narrowing conversion from double to float

Can someone explain why that is and how to correct it?

Narrowing: Float is smaller than double, in a way analogous to int8_t is smaller than int16_t. The biggest float is quite a bit smaller than the biggest double.

Note also: a smaller int will auto magically be promoted to a larger int. Similarly, your compiler did not protest about "double x_pos = clownfish->xPos();", a double is always big enough to contain a float.


how to correct:

If you are confident that float (the smaller) is sufficient for your needs, or you are not allowed to change the clownfish code, then you might consider using a cast.

clownfish->xPos(static_cast<float>(x_pos)).

If you are willing and not prohibited from changing the clownfish code, ensure that the clownfish x position (i.e. what "clownfish->xPos()" returns) is a double, and that the function "clownfish->xPos()" returns a double.

Narrowing conversion from char to double

It is narrowing because the standard says so.

7 A narrowing conversion is an implicit conversion

[...]

(7.3) — from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type [...]

Narrowing is not allowed in list-initialization. Use an explicit conversion (cast).

double a{static_cast<double>(c)};

Yes, theoretically it is allowed for char to be not exactly representable as double, e.g. when both are 32-bit types. This is contrived but the standard allows for such an implementation.

Narrowing conversion of 'int' value to 'short' is not allowed here

Ideally, all GUID fields should be declared unsigned (see for instance this Microsoft documentation). But some languages (Java, for instance) don't support unsigned integers. So it looks like your C++ GUID structure was defined by a Java programmer.

If you can change the definition of GUID, do that. If not, I am afraid you are going to have to apply your (short) cast to all occurrences of the DEFINE_GUID macro (unless your compiler has some way of disabling this error, as suggested in the comments to your original post). Java programmers have to do this all the time.

Narrowing conversions in C++0x. Is it just me, or does this sound like a breaking change?

I ran into this breaking change when I used GCC. The compiler printed an error for code like this:

void foo(const unsigned long long &i)
{
unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32};
}

In function void foo(const long long unsigned int&):

error: narrowing conversion of (((long long unsigned int)i) & 4294967295ull) from long long unsigned int to unsigned int inside { }

error: narrowing conversion of (((long long unsigned int)i) >> 32) from long long unsigned int to unsigned int inside { }

Fortunately, the error messages were straightforward and the fix was simple:

void foo(const unsigned long long &i)
{
unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF),
static_cast<unsigned int>(i >> 32)};
}

The code was in an external library, with only two occurrences in one file. I don't think the breaking change will affect much code. Novices might get confused, though.

Why int is narrowed to float?

That is because of the precision of the float, which is only 7-digit, despite it has larger range than int.

So if you try to represent int number with more than 7-digit precision to float you might likely get some loss. - in this sense it is called narrowed. Though float has wider range than int, it has less precision.

Besides, floating point representation is approximation - that is, it does not represent exact number (except for power of 2). In that sense, the int is also narrowed.



Related Topics



Leave a reply



Submit