考虑两种计算方法:
- 双精度
数据->应用具有双精度临时的
函数->返回结果 - 双精度
数据->铸造到长双
->应用具有长双精度临时的
函数-> 演员加倍
->返回结果
与第一个解决方案相比,第二个解决方案是否可以给出不太准确的结果,如果是,在什么情况下
是的。证明:设 c = 0x1p-53 + 0x1p-64。以双精度和长双精度(通用英特尔格式,具有 64 位有效数)评估 1+c-c-1。在双精度中,结果为 0,这是数学上精确的答案。在长双精度中,结果是 -0x1p-64,这是错误的(并且在转换为双精度时仍然是错误的)。
在双精度中,1+c 将 1 的 ULP(最不高精度单位)的一半多于 1 加一点,因此它产生 1 加上一个 ULP。减去 c 减去略多于一半的 ULP,因此最接近结果的可表示数字(双倍)是 1,因此产生 1。然后减去 1 得到 0。
在长双精度中,1+c 加上 0x1p-53 加上 1 的半个 ULP。 (在长双精度中,1 的 ULP 是 0x1p-63。 由于结果与两个最接近的可表示数字(长双精度)的距离完全相同,因此返回具有低位零的数字 1+0x1p-53。那么减去 c 的确切结果是 1 - 0x1p-64。这是完全可表示的,因此将其返回。最后,减去 1 得到 -0x1p-64。
关于long double
草案说:
3.9.1 基本类型
8 有三种浮点类型:浮点型、双精度型和长型双精度型。双倍类型至少提供 与浮点数一样多的精度,长双精度型至少提供与双精度一样多的精度。 浮点型的值集是双精度类型的值集的子集;值集 双精度类型是长双精度类型的值集的子集。的值表示形式 浮点类型是实现定义的。整型和浮点型统称为算术型 类型。标准模板 std::numeric_limits (18.3) 的专业化应指定最大值 以及实现的每个算术类型的最小值。
至于促销,这是下一个最有趣的部分:
4.6 浮点提升
1 浮点型的 prvalue 可以转换为类型的 prvalue 双。该值保持不变。
2 这种转换称为浮动 积分提升。
请注意,没有关于double
到long double
的任何说明。不过,我会冒着这个错误的风险。
接下来关于转换,当您从long double
转到double
时,这是我们感兴趣的:
4.8 浮点转换
1 浮点类型的 prvalue 可以转换为 另一种浮点类型。如果源值可以完全 在目标类型中表示,转换的结果是 确切的表示。如果源值位于两个相邻值之间 目标值,则转换结果为 实现定义的任一值的选择。否则 行为未定义。
2 允许作为浮点的转换 促销不包括在浮点转换集中。
现在,让我们看看缩小的效果:
6. 缩小转换是隐式转换
[...]
从长双精度到双精度或浮点
- 数,或从双精度到浮点数,除非源是常量表达式并且之后的实际值 转换在可以表示的值范围内(甚至 如果不能准确表示)
从所有这些标准中可以得出两个结论:
- 将有关缩小范围的部分与有关实现定义的转化的部分结合起来,您的结果可能会因平台而异。
- 如果您的中间结果(考虑多个此类结果)在
long double
无法用double
准确表示的范围内(高或低),则这些结果可以累积以返回不同的最终结果,您将希望将其作为double
返回。
至于哪个更准确,我认为这完全取决于您的应用。