C++铸造到更精确的类型并失去准确性



考虑两种计算方法:

  1. 双精度
    数据->应用具有双精度临时的
    函数->返回结果
  2. 双精度
    数据->铸造到长双
    ->应用具有长双精度临时的
    函数-> 演员加倍
    ->返回结果

与第一个解决方案相比,第二个解决方案是否可以给出不太准确的结果,如果是,在什么情况下

是的。证明:设 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 这种转换称为浮动 积分提升。

请注意,没有关于doublelong double的任何说明。不过,我会冒着这个错误的风险。

接下来关于转换,当您从long double转到double时,这是我们感兴趣的:

4.8 浮点转换

1 浮点类型的 prvalue 可以转换为 另一种浮点类型。如果源值可以完全 在目标类型中表示,转换的结果是 确切的表示。如果源值位于两个相邻值之间 目标值,则转换结果为 实现定义的任一值的选择。否则 行为未定义。

2 允许作为浮点的转换 促销不包括在浮点转换集中。

现在,让我们看看缩小的效果:

6. 缩小转换是隐式转换

[...]

    从长双精度到双精度或浮点
  • 数,或从双精度到浮点数,除非源是常量表达式并且之后的实际值 转换在可以表示的值范围内(甚至 如果不能准确表示)

从所有这些标准中可以得出两个结论:

  • 将有关缩小范围的部分与有关实现定义的转化的部分结合起来,您的结果可能会因平台而异。
  • 如果您的中间结果(考虑多个此类结果)在long double无法用double准确表示的范围内(高或低),则这些结果可以累积以返回不同的最终结果,您将希望将其作为double返回。

至于哪个更准确,我认为这完全取决于您的应用。

最新更新