IEEE 754 浮点加法和乘法的互换性

Interchangeability of IEEE 754 floating-point addition and multiplication

IEEE 754 (IEC 559) 浮点标准中,加法 x + x 是否可以与乘法 2 * x 互换?任何保证 case_addcase_mul 总是 给出完全相同的结果?

#include <limits>

template <typename T>
T case_add(T x, size_t n)
{
    static_assert(std::numeric_limits<T>::is_iec559, "invalid type");

    T result(x);

    for (size_t i = 1; i < n; ++i)
    {
        result += x;
    }

    return result;
}

template <typename T>
T case_mul(T x, size_t n)
{
    static_assert(std::numeric_limits<T>::is_iec559, "invalid type");

    return x * static_cast<T>(n);
}

如果 n 例如 pow(2, 54) 那么乘法就可以正常工作,但是在加法路径中,一旦结果值足够大于输入 xresult += x 将产生 result.

是的,但它并不普遍。乘以大于 2 的数字可能不会得到相同的结果,因为您已经更改了指数并且如果您替换为加法可能会下降一点。但是,如果用加法运算代替,乘以二不能下降一点。

如果case_add中的累加器result变得太大,加上x会引入舍入误差。在某个时候,添加 x 根本不会有任何效果。所以函数不会给出相同的结果。

例如如果double x = 0x1.0000000000001p0(十六进制浮点数表示法):

n  case_add              case_mul

1  0x1.0000000000001p+0  0x1.0000000000001p+0
2  0x1.0000000000001p+1  0x1.0000000000001p+1
3  0x1.8000000000002p+1  0x1.8000000000002p+1
4  0x1.0000000000001p+2  0x1.0000000000001p+2
5  0x1.4000000000001p+2  0x1.4000000000001p+2
6  0x1.8000000000001p+2  0x1.8000000000002p+2

Is the addition x + x interchangeable by the multiplication 2 * x in IEEE 754 (IEC 559) floating-point standard

是的,因为它们在数学上是相同的,所以它们会给出相同的结果(因为结果是精确的浮点数)。

or more generally speaking is there any guarantee that case_add and case_mul always give exactly the same result?

一般不会,不会。据我所知,它似乎适用于 n <= 5:

  • n=3:因为x+x是精确的(即不涉及四舍五入),所以(x+x)+x只涉及最后一步的四舍五入。
  • n=4(并且您使用的是默认舍入模式)然后

    • 如果 x 的最后一位为 0,则 x+x+x 是准确的,因此结果与 n=3.
    • 的参数相同
    • 如果最后 2 位是 01,那么 x+x+x 的确切值将具有 1|1 的最后 2 位(其中 | 表示格式中的最后一位),这将四舍五入为 0|0。下一次相加会给出一个准确的结果 |01,因此结果会向下舍入,抵消之前的错误。
    • 如果最后 2 位是 11,那么 x+x+x 的精确值将具有 0|1 的最后 2 位,将向下舍入为 0|0 .下一次加法将给出一个准确的结果 |11,因此结果将向上舍入,再次抵消之前的错误。
  • n=5(再次假设默认舍入):因为 x+x+x+x 是精确的,所以它与 n=3.

    的理由相同

对于 n=6 它失败了,例如将 x 设为 1.00000000000000021.0 之后的下一个 double),在这种情况下 6x6.000000000000002x+x+x+x+x+x6.000000000000001