加法x + x
是否可以通过 IEEE 754(IEC 559)浮点标准中的乘法2 * x
进行互换,或者更一般地说是case_add
可以保证case_mul
1}}和#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);
}
总是给出完全相同的结果?
# "Run application specific configuration scripts"
- include: "app_cfg/{{ app_name }}.yml"
when: "{{ app_conf[app_name].app_cfg }}"
ignore_errors: no
tags:
- conf
答案 0 :(得分:9)
加法
x + x
是否可以通过IEEE 754(IEC 559)浮点标准中的乘法2 * x
进行互换
是的,因为它们在数学上都是相同的,所以它们会给出相同的结果(因为结果是精确的浮点数)。
或更一般地说,是否保证case_add和case_mul总能给出完全相同的结果?
一般情况下,不是。据我所知,它似乎适用于n <= 5
:
n=3
:由于x+x
是准确的(即不涉及舍入),因此(x+x)+x
只涉及最后一步的四舍五入。 n=4
(您正在使用默认的舍入模式),然后
x
的最后一位为0,则x+x+x
是准确的,因此结果与n=3
的参数相同。01
,那么x+x+x
的确切值将具有1|1
的最后2位(其中|表示格式中的最后一位),这将是被舍入到0|0
。下一个添加将给出一个精确的结果|01
,因此结果将向下舍入,取消之前的错误。11
,则x+x+x
的确切值将包含0|1
的最后2位,其将向下舍入为0|0
。下一个添加将给出精确结果|11
,因此结果将向上舍入,再次取消之前的错误。 n=5
(同样,假设默认舍入):由于x+x+x+x
是准确的,因此与n=3
的原因相同。
对于n=6
,它失败了,例如取x
为1.0000000000000002
(double
之后的下一个1.0
),在这种情况下,6x
为6.000000000000002
,x+x+x+x+x+x
为6.000000000000001
答案 1 :(得分:3)
如果n
例如pow(2, 54)
,那么乘法就可以了,但是在结果值远大于输入x
时,在加法路径中,{{1}将产生result += x
。
答案 2 :(得分:1)
是的,但它并不普遍。乘以高于2的数字可能不会给出相同的结果,因为您更改了指数,如果替换为adds,则可能会略微下降。但是,如果由添加操作替换,则乘以2不会丢失一点。
答案 3 :(得分:1)
如果result
中的累加器case_add
变得太大,添加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