MSVC使用双精度浮点数进行花括号初始化似乎违反了标准?

10

看看这个简单的程序:

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中测试),仅有未使用变量的警告。此外,删除或注释掉f4f6行会导致成功编译(只有对于f2行的一个警告)。

最初看起来像是MSVC告诉我7.2不能精确地表示为float,所以它是一次缩小转换(在大括号初始化中是非法的)。然而,标准(draft N3337),第8.5.4节,注7说:

缩小转换是一种隐式转换...

  • long doubledoublefloat,或者从doublefloat,除非源是常数表达式并且转换后的实际值在可表示值的范围内(即使不能完全表示

重点是我的。由于7.2在float可表示的值范围内,根据标准,其转换为float不应是一次缩小转换。MSVC这里错了吗?我应该提交一个错误报告吗?


Imo 2015在收窄转换警告方面有些过度了,所以请提交错误报告 :) - Jonathan Potter
哦,我对警告还算能够接受。但是我无法忍受错误。我的代码库有很多浮点数和双精度常量(数学代码棒极了),所以找到只有浮点常量并为每个常量添加“f”将会非常非常烦人。 - nneonneo
请尝试使用/W4 - Richard Critten
@RichardCritten:相同的结果。 - nneonneo
1
为什么不在文字的末尾加上 f 呢? - Chris Beck
2个回答

6

看起来确实是个bug。为了解决此问题,以下方法可以消除MSVC 2015中的所有错误和警告。

#pragma float_control(precise, off, push)

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

#pragma float_control(precise, pop)

如果使用/fp:fast编译器开关,在全球范围内同样有效,但该开关与/Za不兼容,后者会禁用MS语言扩展。


1
哦,float_control pragma 的注释写得很好 - 我之前不知道这个! - nneonneo

-3

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

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

float f4{ 7.2f };

2
无效的拒绝代码的理由,请参见上面的标准引用或N4141中的8.5.4/7。 - Baum mit Augen
@BaummitAugen 这可能不是一个有效的理由,但只要有一个编译器生成这个错误,就应该有一个相应的解释。而且我提供的修复方法完美地解决了这个问题。 - Mark Ransom
7.2 无法精确表示的观察已经是问题和标准引用的一部分。 - Anedar
@Anedar 这个回答本来是针对另一个问题的,但 Baum mit Augen 把它关闭了,说是重复的 - 我别无选择,只能把它放在这里。而且我肯定不知道为什么我会被惩罚,因为我没有说任何错误的话! - Mark Ransom
嗯,我看到问题所在了:另一个问题并不是完全相同的重复,而且会被你的答案回答。只将其标记为此问题的副本也应该回答它(如果提问者仔细阅读此问题)。然而,对于直接进入此问题的人来说,你的答案似乎有些偏差。Meta问题? - Anedar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接