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