4

给定如下代码段,我只想知道

  • 为什么 long double 的最大值在 64 位中小于 32 位?
  • 为什么 64 位版本不能像 32 位版本那样扩展尽可能多的数字来填充“40”精度输出?
  • 似乎 LDBL_MIN 和 LDBL_MAX 的值相等,这是一个错误吗?

我查看了机器中的 float.h 文件,但找不到这些宏常量的显式定义。

测试代码(平台= Win7-64bit)

#include <cfloat>
#include <iomanip>
cout<<"FLT_MAX   ="<< setprecision(40) << FLT_MAX  << endl;
cout<<"DBL_MAX   ="<< setprecision(40) << DBL_MAX  << endl;
cout<<"LDBL_MAX  ="<< setprecision(40) << LDBL_MAX << endl;
cout<<"FLT_MIN   ="<< setprecision(40) << FLT_MIN  << endl;
cout<<"DBL_MIN   ="<< setprecision(40) << DBL_MIN  << endl;
cout<<"LDBL_MIN  ="<< setprecision(40) << LDBL_MIN << endl;

32 位结果 (MinGW-20120426)

FLT_MAX  =340282346638528859811704183484516925440
DBL_MAX  =1.797693134862315708145274237317043567981e+308
LDBL_MAX =1.189731495357231765021263853030970205169e+4932
FLT_MIN  =1.175494350822287507968736537222245677819e-038
DBL_MIN  =2.225073858507201383090232717332404064219e-308
LDBL_MIN =3.362103143112093506262677817321752602598e-4932

64 位结果 (MinGW64-TDM 4.6)

FLT_MAX  =340282346638528860000000000000000000000
DBL_MAX  =1.7976931348623157e+308
LDBL_MAX =1.132619801677474e-317
FLT_MIN  =1.1754943508222875e-038
DBL_MIN  =2.2250738585072014e-308
LDBL_MIN =1.132619801677474e-317

谢谢。

[编辑]:使用最新的 MinGW64-TGM 4.7.1,LDBL_MAX、LDBL_MIN 的“错误”似乎已删除。

4

2 回答 2

3

LDBL_MAX =1.132619801677474e-317听起来像是某个地方的错误。标准的要求是每个可以表示为 a 的值double也可以表示为 a long double,所以它是不允许的LDBL_MAX < DBL_MAX。鉴于您没有显示您的真实测试代码,我个人会在指责编译器之前检查一下。

如果两者之间确实存在(非错误)差异long double,那么差异的基础将是您的 32 位编译器使用较旧的 x87 浮点运算,它具有 80 位精度,因此允许 80位long double

您的 64 位编译器使用 x64 中较新的 64 位浮点运算。没有 80 位精度,也不需要切换到 x87 指令来实现更大的long double.

可能比这更复杂。例如,并非所有 x86 编译器都必须具有 80 位long double. 他们如何做出决定取决于各种因素,可能包括 SSE2 具有 64 位浮点运算的事实。但可能性是long double与 大小相同double,或者更大。

为什么 64 位版本不能像 32 位版本那样扩展尽可能多的数字来填充“40”精度输出?

双精度只有大约 15 个十进制数字。超出此范围的数字有时会提供信息,但通常会产生误导。

我不记得标准是怎么说的setprecision,但是假设允许实现在停止生成数字的地方画一条线,那么 a 的精度double是画它的合理位置。至于为什么一个实现决定实际这样做而另一个没有——我不知道。由于它们是不同的发行版,它们可能使用完全不同的标准库。

同样的“虚假精度”是您在一种情况下看到340282346638528859811704183484516925440FLT_MAX 而在另一种情况下看到的原因340282346638528860000000000000000000000。一个编译器(或者更确切地说,一个库实现)已经麻烦地计算了很多数字。另一个早早放弃,四舍五入。

于 2012-10-03T10:55:59.690 回答
0

为了回答这个问题,我只做了几个假设:1)你只在 64 位机器上测试了这个 2)编译器是同一个子版本的不同位版本(也就是说,它们实际上是姐妹编译器)。

话虽如此:

来自“ISO/IEC 14882 国际标准第一版 1998-09-01”

3.9.1 基本类型

  1. 有三种浮点类型:float、double 和 long double。double 类型提供的精度至少与 float 一样,long double 类型提供的精度至少与 double 一样。float 类型的值集是 double 类型的值集的子集;double 类型的值集是 long double 类型的值集的子集。浮点类型的值表示是实现定义的。整数和浮点类型统称为算术类型。标准模板 numeric_limits (18.2) 的特化应指定实现的每种算术类型的最大值和最小值。

此外,就更高级别数字的精度而言,不同的 CPU 将对最终结果产生不同的影响。编译器也是如此。VC++ 的编译器与 borland 不同,GCC/G++ 等也不同。

于 2012-10-03T10:33:39.813 回答