MSVC brace initialization with doubles appears to violate the standard?
Asked Answered
W

2

11

Check out this simple program:

int main() {
    float f2 = 7.2; // OK, with warning
    float f3 = 7.199999809265137; // OK, no warning
    float f4{ 7.2 }; // Fails
    float f5{ 7.199999809265137 }; // OK, no warning
    float f6 = { 7.2 }; // Fails
    float f7 = { 7.199999809265137 }; // OK, no warning
}

When compiled with MSVC 2015 using the default options (cl /W4, version 19.00.23918), I get the following messages:

FloatTest.cpp(2): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(4): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(4): warning C4305: 'initializing': truncation from 'double' to 'float'
FloatTest.cpp(6): error C2397: conversion from 'double' to 'float' requires a narrowing conversion
FloatTest.cpp(6): warning C4305: 'initializing': truncation from 'double' to 'float'

This program compiles fine with Clang 3.0-3.8 and GCC 4.5.4-6.1.0 (tested with http://melpon.org/wandbox), with only warnings for unused variables. Further, removing/commenting out lines f4 and f6 result in successful compilation (with only the one warning for line f2).

Initially it looks like MSVC is just telling me that 7.2 can't be represented precisely as a float, so it's a narrowing conversion (which is illegal in brace initialization). However, the standard (draft N3337), section 8.5.4, note 7, says this:

A narrowing conversion is an implicit conversion...

  • from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly)

Emphasis mine. Since 7.2 is within the range of values representable by float, its conversion to float should not be a narrowing conversion according to the standard. Is MSVC in the wrong here, and should I file a bug?

Woolsack answered 8/7, 2016 at 21:17 Comment(5)
Imo 2015 went overboard with narrowing-conversion warnings, so yes please file a bug report :)Yoshida
Oh, I'm mostly cool with warnings. It's the errors I can't stand. My codebase has a ton of float and double constants (yay for math code), so finding only the float constants to append "f" to each one is going to be very, very annoying.Woolsack
Try with /W4 as well please.Elboa
@RichardCritten: Same result.Woolsack
Why don't you just put f at the end of the literals?Monophysite
A
6

It looks like a bug, indeed. For a workaround, the following appears to silence both errors and warnings in MSVC 2015.

#pragma float_control(precise, off, push)

float f2 = 7.2; // OK, with warning
//...

#pragma float_control(precise, pop)

The same works globally if using the /fp:fast compiler switch, though that one is incompatible with /Za which disables MS language extensions.

Artifice answered 9/7, 2016 at 0:16 Comment(1)
Oh, nice note about the float_control pragma - I did not know that!Woolsack
A
-3

Some floating point numbers can be exactly expressed in a float representation and some can't. If the number can be represented in the form x / 2^y where x is any integer and y is an integer 23 or less, it fits. Most decimal numbers can't be represented in this way, as a binary number they repeat forever. 7.2 is one example.

You can fix this easily by appending f to each number, to indicate to the compiler that this is a float constant rather than a double.

float f4{ 7.2f };
Ackack answered 19/9, 2017 at 15:37 Comment(5)
Not a valid reason to reject the code, see the standard quote above or 8.5.4/7 in N4141.Warty
@BaummitAugen it may not be a valid reason, but as long as there's a compiler out there that generates this error there should be an explanation to match it. And certainly the fix I give works perfectly.Ackack
The observation that 7.2 can't be represented exactly is already part of the question and the standard quote.Euripus
@Euripus this answer was intended to go to a different question, but Baum mit Augen closed it as a duplicate - I had no choice but to put it here. And I certainly don't know why I'm being punished when I didn't say anything false!Ackack
Hmm, i see the problem: The other question is not an exact duplicate and would be answered with your answer. Just marking it as a duplicate of this question should also answer it (if the asker reads this question carefully). As someone who came directly to this question, your answer seems way off though. Case for Meta?Euripus

© 2022 - 2024 — McMap. All rights reserved.