C++ 对本周大师的理解#67:双倍还是零
最近,我在读一篇帖子: 我对以下程序的解释有点困惑:C++ 对本周大师的理解#67:双倍还是零,c++,floating-point,precision,gotw,C++,Floating Point,Precision,Gotw,最近,我在读一篇帖子: 我对以下程序的解释有点困惑: int main() { double x = 1e8; while( x > 0 ) { --x; } } 假设此代码在某些机器上运行1秒。我同意这样的代码是愚蠢的 然而,根据对问题的解释,如果我们将x从float更改为double,那么在某些编译器上,它将使计算机永远运行。该解释基于本标准的以下引用 >强引用> C++标准3.91/8的引用:< /强> 有三种浮点类
int main()
{
double x = 1e8;
while( x > 0 )
{
--x;
}
}
假设此代码在某些机器上运行1秒。我同意这样的代码是愚蠢的
然而,根据对问题的解释,如果我们将x
从float
更改为double
,那么在某些编译器上,它将使计算机永远运行。该解释基于本标准的以下引用
<> >强引用> C++标准3.91/8的引用:< /强>
有三种浮点类型:浮点型、双精度型和长双精度型。double类型提供的精度至少与float类型相同,long double类型提供的精度至少与double类型相同。float类型的值集是double类型的值集的子集;double类型的值集是long double类型的值集的子集
守则的问题是:
如果将“double”更改为“float”,预计需要多长时间?为什么?
以下是解释:
它可能需要大约1秒(在特定的实现中,浮点可能比double快一些、快一些或慢一些),也可能需要永远,这取决于float是否能够准确地表示从0到1e8(包括0到1e8)的所有整数值
标准中的上述引用意味着可能存在可以用double表示但不能用float表示的值。特别是,在一些流行的平台和编译器上,double可以精确地表示[0,1e8]中的所有整数值,但float不能
如果float不能准确地表示从0到1e8的所有整数值,该怎么办?然后,修改后的程序将开始倒计时,但最终将达到一个无法表示的值N,其N-1==N(由于浮点精度不足)。。。及
我的问题是:
如果float甚至不能表示1e8
,那么我们在初始化float x=1e8
时应该已经有溢出;那我们怎么能让电脑永远运行呢?
我在这里尝试了一个简单的例子(虽然不是double
,而是int
)
#包括
int main()
{
INTA=44444;
std::cout试试这个简单的修改,它可以计算连续x值的值
#include <iostream>
using namespace std;
int main()
{
float x = 1e8;
while( x > 0 )
{
cout << x << endl;
--x;
}
}
#包括
使用名称空间std;
int main()
{
浮点数x=1e8;
而(x>0)
{
关键词是“准确”
float
可以准确地表示1e8
,除非您有一个畸形的float
类型。但这并不意味着它可以准确地表示所有较小的值,例如,通常需要26位精度的2^25+1=33554433
,不能在float
中准确地表示(通常,它有23+1位精度),也不能2^25-1=33554431
,这需要25位精度
然后,这两个数字都表示为2^25=33554432
,然后
33554432.0f - 1 == 33554432.0f
will循环。(您将在前面遇到一个循环,但该循环具有良好的十进制表示形式;)
在整数算术中,所有的x
都有x-1!=x
,但在浮点算术中没有
请注意,即使float
只有通常的23+1位精度,循环也可能结束,因为标准允许以比类型更高的精度执行浮点计算,并且如果以足够高的精度执行计算(例如,通常的double
52+1位),每一次减法都会改变x
,感谢您提供的好信息,但我的问题是,为什么即使我们在初始化时有溢出,while循环也会启动?@taocp您在初始化时没有溢出。浮点格式的精度会随着值的增加而不断降低,直到达到+1为止。#INF.Ope无限和NAN的定量是合法的,而不是未定义的。但它们可能会产生意想不到的结果。请看
33554432.0f - 1 == 33554432.0f