c++ - 微软edX C++课程:double vs long double——为什么缺少通用标准?
问题描述
我决定在 edX 上学习微软的 C++ 课程。根据他们的说法,大小double
和long double
范围相同:
这与这些规范相矛盾: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)”之类的东西。
解决方案
根据他们的说法,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 位长双精度
也可以看看
- C++ 中的 long double 是 IEEE 的 binary128 的实现吗?
- long double 的性能影响。为什么C默认选择64位而不是硬件的80位?
- 80 位扩展精度数据类型的应用/好处是什么?
- C和C++中long double和double的区别
- 我想知道 long double 和 double 之间的区别
- C++ 中的 long double 是 IEEE 的 binary128 的实现吗?
1见
2见
推荐阅读
- javascript - 将数字乘以 document.getElementById('myid') 时获取 NaN 值
- r - cplot R 因子 2 类别的边际效应
- python - seaborn violinplot:FutureWarning:将以下变量作为关键字arg传递:x。从 0.12 版本开始,唯一有效的位置参数将是“数据”
- xamarin.forms - 如何解决 xamarin.forms 中的此错误类型“ObfuscationAttribute”都存在于两者中
- python - Python:第 3 级嵌套列表理解未按预期运行
- c++ - 使用重载运算符 [] 更改结构的值
- numpy - 如何找到经过训练的 CNN/ANN 模型的位值(精度)?
- c - 在 C 中以规范顺序排列多项式
- post - 试图在 php 中读取 python 发送的 Post 请求
- sql-server - PowerShell :: SQL SELECT 仅返回第一行