Инициализация фигурной скобки MSVC с двойными значениями нарушает стандарт?

Проверьте эту простую программу:

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
}

При компиляции с MSVC 2015 с параметрами по умолчанию (cl /W4, версия 19.00.23918) я получаю следующие сообщения:

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'

Эта программа отлично компилируется с Clang 3.0-3.8 и GCC 4.5.4-6.1.0 (проверено с помощью http://melpon.org/wandbox ), с предупреждениями только о неиспользуемых переменных. Кроме того, удаление/комментирование строк f4 и f6 приводит к успешной компиляции (только с одним предупреждением для строки f2).

Сначала кажется, что MSVC просто говорит мне, что 7.2 не может быть представлено именно как float, так что это сужающее преобразование (что недопустимо при инициализации фигурных скобок). Однако стандарт (проект N3337), раздел 8.5. 4, примечание 7, говорит следующее:

Сужающее преобразование – это неявное преобразование...

  • от long double до double или float или от double до float, за исключением случаев, когда источником является постоянное выражение, а фактическое значение после преобразования находится в пределах диапазона значений, которые могут быть представлены (даже если оно не может быть точно представлено)

Акцент мой. Поскольку 7.2 находится в диапазоне значений, представляемых float, его преобразование в float не должно быть сужающим преобразованием в соответствии со стандартом. Является ли MSVC неправильным здесь, и я должен сообщить об ошибке?


person nneonneo    schedule 08.07.2016    source источник
comment
Imo 2015 переборщил с предупреждениями о сужении конверсии, так что да, пожалуйста, отправьте отчет об ошибке :)   -  person Jonathan Potter    schedule 09.07.2016
comment
О, я обычно спокойно отношусь к предупреждениям. Это ошибки, которых я не выношу. В моей кодовой базе куча констант с плавающей запятой и двойных чисел (да, для математического кода), поэтому поиск только констант с плавающей запятой для добавления f к каждой из них будет очень, очень раздражающим.   -  person nneonneo    schedule 09.07.2016
comment
Попробуйте также с /W4, пожалуйста.   -  person Richard Critten    schedule 09.07.2016
comment
@RichardCritten: тот же результат.   -  person nneonneo    schedule 09.07.2016
comment
Почему бы вам просто не поставить f в конце литералов?   -  person Chris Beck    schedule 09.07.2016


Ответы (2)


Это действительно похоже на ошибку. В качестве обходного пути в MSVC 2015 появляется следующее, чтобы заглушить как ошибки, так и предупреждения.

#pragma float_control(precise, off, push)

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

#pragma float_control(precise, pop)

То же самое работает глобально, если используется параметр компилятора /fp:fast, хотя он несовместим с /Za, который отключает языковые расширения MS.

person dxiv    schedule 09.07.2016
comment
О, хорошее замечание о прагме float_control — я этого не знал! - person nneonneo; 09.07.2016

Некоторые числа с плавающей запятой могут быть точно выражены в представлении float, а некоторые нет. Если число может быть представлено в виде x / 2^y, где x — любое целое число, а y — целое число 23 или меньше, оно подходит. Большинство десятичных чисел не могут быть представлены таким образом, поскольку двоичные числа повторяются бесконечно. 7.2 является одним из примеров.

Это можно легко исправить, добавив f к каждому числу, чтобы указать компилятору, что это константа float, а не double.

float f4{ 7.2f };
person Mark Ransom    schedule 19.09.2017
comment
Не является веской причиной для отклонения кода, см. стандартную цитату выше или 8.5.4/7 в N4141. - person Baum mit Augen; 19.09.2017
comment
@BaummitAugen это может быть неуважительной причиной, но пока есть компилятор, который генерирует эту ошибку, должно быть объяснение, соответствующее ей. И, конечно же, исправление, которое я даю, работает отлично. - person Mark Ransom; 19.09.2017
comment
Замечание о том, что 7.2 не может быть точно представлено, уже является частью вопроса и стандартной цитаты. - person Anedar; 19.09.2017
comment
@Anedar, этот ответ предназначался для другого вопроса, но Baum mit Augen закрыл его как дубликат - у меня не было другого выбора, кроме как поместить его здесь. И я уж точно не знаю, за что меня наказывают, если я не сказал ничего ложного! - person Mark Ransom; 19.09.2017
comment
Хм, я вижу проблему: другой вопрос не является точной копией, и на него будет дан ваш ответ. Просто пометив его как дубликат этого вопроса, вы также должны ответить на него (если спрашивающий внимательно прочитает этот вопрос). Как человек, который пришел непосредственно к этому вопросу, ваш ответ кажется далеким. Дело для Меты? - person Anedar; 19.09.2017