首页 > 解决方案 > 微软edX C++课程:double vs long double——为什么缺少通用标准?

问题描述

我决定在 edX 上学习微软的 C++ 课程。根据他们的说法,大小doublelong double范围相同:

edX 上的 Microsoft C++

这与这些规范相矛盾:https ://en.wikipedia.org/wiki/C_data_types

起初,我以为微软打错了,但后来我发现了这篇文章

在 x86 架构上,大多数编译器将 long double 实现为该硬件支持的 80 位扩展精度类型(有时存储为 12 或 16 字节以维护数据结构

编译器还可以将 long double 用于 128 位四倍精度格式,目前在软件中实现。

换句话说,是的,long double 可能能够存储比 double 更大范围的值。但这完全取决于编译器。

所以,我想,在大多数情况下(即在大多数编译器实现中),微软是错误的,但在某些情况下他们可能是正确的。

但后来我回顾了 C++ 11 标准。这里是它所说的:

有三种浮点类型:float、double 和 long double。double 类型提供的精度至少与 float 一样,long double 类型提供的精度至少与 double 一样。float 类型的值集是 double 类型的值集的子集;double 类型的值集是 long double 类型的值集的子集。

模糊,对吧?

所以,问题来了:C++ 已经存在了很长时间。为什么这种东西仍然没有可靠的通用标准?是否为了灵活性而故意 - 每个人都自己决定这些数据类型将是什么。还是他们无法让所有人都参与进来?

PS我仍然认为微软应该用不同的方式写出来:类似于“long double is the same size as double or more (up to ... bytes)”之类的东西。

标签: c++typesedxlong-double

解决方案


根据他们的说法,double 和 long double 在大小和范围上是相同的(见下面的截图)。这与这些规格相矛盾:

这里没有矛盾。如果您仔细阅读了标准链接的文章,您会发现C 标准指定了最小可能的类型范围,而不是它们的一些固定大小。另请注意,上面的 wiki 链接适用于 C 而不是 C++。它们是非常不同的语言。幸运的是,他们都同意类型的大小

这允许灵活性,因为 C 和 C++ 一直是为可移植性而设计的。主要理念是“你不用为你不使用的东西付费”,因此编译器实现必须为每个特定架构选择最好和最有效的东西。他们不能强迫int总是 32 位长。int例如,在 18 位架构上,int 将具有 18 位而不是笨拙的 32 位大小,并且如果定义为 16 位类型,16 位 CPU 将不必浪费支持 32 位 int 的周期

这就是为什么 C 和 C++ 允许有符号整数类型使用 1 的补码和符号幅度,而不仅仅是 2 的补码。浮点类型也没有强制要求具有固定大小或二进制,因此实现可以使用十进制浮点类型。事实上,甚至不需要 IEEE-754,因为有些计算机使用其他浮点格式。请参阅是否有任何真实世界的 CPU 不使用 IEEE 754?

所以阅读ISO/IEC 9899:201x C++ 标准,第 5.2.4.2.1 节(整数类型的大小<limits.h>)我们知道:

下面给出的值应替换为适用于#if预处理指令的常量表达式。[…]它们的实现定义值的大小(绝对值)应等于或大于所示值,符号相同

对应的值INT_MAX是 32767,这意味着INT_MAX >= 32767在任何符合要求的实现中。同样的事情也适用于第 5.2.4.2.2 节中的浮点类型(Characteristics of floating types <float.h>

你在标准中读到的意思是

  • PrecisionOf(float) ⩽precisionOf(double) ⩽precisionOf(long double) 和
  • setOfValues(float) ⊂ setOfValues(double) ⊂ setOfValues(long double)

它非常清楚,一点也不含糊。事实上,你只保证有

  • CHAR_BIT ⩾ 8
  • sizeof(char) ⩽ sizeof(short) ⩽ sizeof(int) ⩽ sizeof(long) ⩽ sizeof(long long)
  • sizeof(float) ⩽ sizeof(double) ⩽ sizeof(long double)
  • FLT_DECIMAL_DIG ⩾ 6
  • LDBL_DECIMAL_DIG ⩾ DBL_DECIMAL_DIG ⩾ 10

因此double允许具有与 相同的大小和精度long double。事实上,在非 x86 平台上它们通常是相同的类型,因为它们没有像 x86这样的扩展精度类型。最近许多实现已经切换到基于软件的 IEEE-754四倍精度for long double,但当然它会慢很多

因为 有许多可能的格式long double,所以也有多种选择long double大小的选项,例如当人们不需要额外的精度或不希望软件实现的性能不佳时。例如

  • x86的GCC-mlong-double-64/80/128取决于您是否需要 64 位(即与 相同double)、80 位(扩展精度)或 128 位(四倍精度)long double。同样,-m96/128bit-long-double如果您想用速度换取 25% 的内存使用率,也有一些选项
  • PowerPC-mabi=ibmlongdouble/ieeelongdouble的GCC具有双双实现或标准四倍精度格式,其范围更广,精度略高,但速度要慢得多

C++ 已经存在了很长时间。为什么这种东西仍然没有可靠的通用标准?是否为了灵活性而故意 - 每个人都自己决定这些数据类型将是什么

确切地说,正如我上面所说,这是为了灵活性而故意的。当您不需要高于double. 标准委员会关心所有可能的架构,包括一些可能已死的架构1

事实上,当 FLT_EVAL_METHOD = 2 时,允许更高long double有时会导致意想不到的结果float,因为anddouble操作也是以更高的精度完成的,所以不同点的相同表达式可能会有不同的结果。此外,不可能对奇数扩展精度long double数学2进行矢量化,这会导致性能更差。因此即使在 x86 MS 的 cl.exe 编译器中也完全禁用了 80 位长双精度

也可以看看


1


2


推荐阅读