使用双精度的 MSVC 大括号初始化似乎违反了该标准

MSVC brace initialization with doubles appears to violate the standard?

本文关键字:标准 初始化 双精度 MSVC      更新时间:2023-10-16

看看这个简单的程序:

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
}
使用

默认选项(cl /W4,版本19.00.23918)使用MSVC 2015编译时,我收到以下消息:

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 doubledoublefloat 或从 doublefloat ,除非源是常量表达式并且转换后的实际值在可以表示的值范围内(即使不能精确表示

强调我的。由于 7.2 在 float 表示的值范围内,根据标准,它转换为 float 不应该是缩小的转换。MSVC 在这里是错误的吗,我应该提交错误吗?

它看起来像一个错误,确实。对于解决方法,以下内容似乎可以消除 MSVC 2015 中的错误和警告。

#pragma float_control(precise, off, push)
float f2 = 7.2; // OK, with warning
//...
#pragma float_control(precise, pop)

如果使用 /fp:fast 编译器开关,则全局工作相同,尽管该开关与禁用 MS 语言扩展的/Za不兼容。

有些浮点数可以用float表示形式精确表示,有些则不能。如果数字可以用x / 2^y的形式表示,其中x是任何整数,y是整数 23 或更小,则它适合。大多数十进制数不能以这种方式表示,作为二进制数,它们永远重复。 7.2就是一个例子。

您可以通过将f附加到每个数字来轻松解决此问题,以向编译器指示这是一个float常量而不是double

float f4{ 7.2f };