45
static_assert(sizeof(unsigned) == 4, ":(");
static_assert(sizeof(double) == 8 ,":(");
unsigned u{42};
double x{u};

g++ 4.7.1 complains about this code:

warning: narrowing conversion of 'u' from 'unsigned int' to 'double' inside { }

Why is this a narrowing conversion? Isn't every unsigned perfectly representable as a double?

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 1
    http://msdn.microsoft.com/en-us/library/s086ab1z(v=vs.71).aspx The maximum value for type double is: 1.79769e+308, unsigned int is 0xFFFFFFFF.. so no it isn't perfectly representable as a double. – paulm Jul 17 '12 at 11:00
  • 1
    This looks like it might be related: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49793. – Oliver Charlesworth Jul 17 '12 at 11:01
  • 7
    @paulm: Huh? A `double` has a 53-bit mantissa, so can definitely represent all 32-bit unsigned ints. – Oliver Charlesworth Jul 17 '12 at 11:02
  • 2
    @OliCharlesworth: An IEEE binary64 `double` might do, but C++ doesn't require IEEE arithmetic, or 64-bit `double`, or 32-bit `unsigned`. – Mike Seymour Jul 17 '12 at 11:04
  • 4
    @MikeSeymour: Sure. But is the compiler required to warn about the general case? – Oliver Charlesworth Jul 17 '12 at 11:08
  • @OliCharlesworth: It's not required to warn about anything; but a warning about narrowing conversions probably should warn about all narrowing conversions, including this one. – Mike Seymour Jul 17 '12 at 11:10

3 Answers3

48

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.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • `s/52/53/`: IEEE 754 binary64 has 53-bit significand, with 52 bits stored and 1 implicit. – Ruslan Jul 09 '19 at 13:25
  • 3
    The most ridiculous is that even `char x='3'; double y{x};` is also a narrowing conversion error. Conversion from `char` to `double` is a narrowing conversion! – Ruslan Jul 09 '19 at 13:42
4

The warning you have because you initialize x with non-constant expression

Ilyas-iMac:TestC++11 sandye51$ cat main.cpp                   
int main()
{
    static_assert(sizeof(unsigned) == 4, ":(");
    static_assert(sizeof(double) == 8 ,":(");
    constexpr unsigned u{42};
    double x{u};

    return 0;
}Ilyas-iMac:TestC++11 sandye51$ gcc -o main main.cpp -std=c++11
Ilyas-iMac:TestC++11 sandye51$ 

As you can see the code above works without any warning or errors

Ilya Lavrenov
  • 347
  • 1
  • 2
  • 7
1

(Let's try:) double has exactly 52 bits of significant (binary) digits (according to ieee standard), whereas unsigned int may have good 64 bits on some other system. So the actual unsigned int's width on your system may be of no value for this check.

Vlad
  • 35,022
  • 6
  • 77
  • 199