我偶然发现了一个我认为不必要的功能,这通常使我感到恐惧:
float coerceToFloat(double x) {
volatile float y = static_cast<float>(x);
return y;
}
然后这样使用:
// double x
double y = coerceToFloat(x);
与做这件事有什么不同吗?:
double y = static_cast<float>(x);
目的似乎是将双精度分解为单精度。闻起来像是出于极端的妄想症。
答案 0 :(得分:12)
static_cast<float>(x)
来消除所有多余的精度,从而产生float
。尽管C ++标准通常允许实现在表达式中保留多余的浮点精度,但是必须由强制转换和赋值运算符删除该精度。
使用更高精确度的许可证在C ++ N4659草案第8条第13款中:
浮动操作数的值和浮动表达式的结果可以更大的形式表示 精度和范围超出类型要求;类型不会因此更改。 64
脚注64说:
强制转换和赋值运算符仍必须按照8.4、8.2.9和8.18中所述执行其特定的转换。
答案 1 :(得分:11)
紧跟@NathanOliver的评论,允许编译器以比操作数类型更高的精度进行浮点数学运算。通常在x86上,这意味着它们将所有操作都作为80位值执行,因为这是硬件中最高效的。只有在存储值时才必须将其还原为类型的实际精度。即使这样,大多数编译器默认仍会进行违反该规则的优化,因为强制精度更改会减慢浮点运算的速度。在大多数情况下都可以,因为额外的精度无害。如果您是坚持不懈的人,则可以使用命令行开关强制编译器遵守该存储规则,并且您可能会发现浮点计算的速度明显降低。
在该函数中,标记变量volatile
告诉编译器它不能逃避存储该值。反过来,这意味着它必须降低传入值的精度以匹配其存储在其中的类型。因此希望这将强制截断。
而且,不,编写强制转换而不是调用该函数是不一样的,因为如果编译器确定可以生成更好的代码,则编译器(在其非一致性模式下)可以跳过对y
的赋值而不存储值,它也可以跳过截断。请记住,目标是尽可能快地运行浮点计算,并且必须处理有关降低中间值精度的琐碎规则,这只会减慢速度。
在大多数情况下,严重的浮点应用程序需要通过跳过中间的截断来实现平坦运行。要求对存储进行截断的规则比现实的要求更有希望。
附带说明,Java最初要求所有浮点数学运算必须以所涉及的类型所需的精确度进行。您可以通过告诉英特尔不要将fp类型扩展到80位来实现。数字处理者大声抱怨,因为这使得计算很多变慢了。 Java很快改变为“严格” fp和“非严格” fp的概念,严重的数字运算使用了非严格的,即使其与硬件支持一样快。完全了解浮点数学(不包括我在内)的人想要速度,并且知道如何应对结果的精度差异。答案 2 :(得分:8)
某些编译器具有“扩展精度”的概念,其中double携带超过64位的数据。这导致浮点计算与IEEE标准不匹配。
以上代码可能是为了防止编译器上的扩展精度标志消除精度损失。此类标志明显违反了double和浮点值的精度假设。似乎他们不会对volatile
变量这样做。
答案 3 :(得分:6)
无论是否允许优化此类转换,它都会发生,而可变分配会阻止其发生。
例如,使用/Ox /fp:fast
的32位MSVC编译(因此使用x87):
_x$ = 8 ; size = 8
float uselessCast(double) PROC ; uselessCast
fld QWORD PTR _x$[esp-4]
ret 0
float uselessCast(double) ENDP ; uselessCast
_y$ = 8 ; size = 4
_x$ = 8 ; size = 8
float coerceToFloat(double) PROC ; coerceToFloat
fld QWORD PTR _x$[esp-4]
fstp DWORD PTR _y$[esp-4]
fld DWORD PTR _y$[esp-4]
ret 0
float coerceToFloat(double) ENDP
uselessCast
如下,coerceToFloat
如下。
float uselessCast(double x)
{
return static_cast<float>(x);
}
类似地,GCC和Clang使用-O3 -ffast-math -m32 -mfpmath=387
uselessCast(double):
fld QWORD PTR [esp+4]
ret
coerceToFloat(double):
sub esp, 20
fld QWORD PTR [esp+24]
fstp DWORD PTR [esp+12]
fld DWORD PTR [esp+12]
add esp, 20
ret
Godbolt link for all the above
当然,您可能会争辩说,对于/fp:fast
或-ffast-math
,无论如何您都不应该对浮点算术有所期望,但是您可能会需要它,但仍然可以舍弃多余的精度。