这是浮点融合乘加的预期行为吗



我有三个使用(32位)浮点精确表示的数字:

x = 16277216, y = 16077216, z = -261692320000000

我期望执行融合乘加x*y+z,以返回数学上正确的值,但四舍五入。正确的数学值是-2489344,不需要四舍五入,因此这应该是融合乘加的输出。但是当我执行fma(x,y,z)时,结果是-6280192。为什么?

我用的是铁锈。注意,z-x*y的四舍五入结果。

let x: f32 = 16277216.0;
let y: f32 = 16077216.0;
let z = - x * y;
assert_eq!(z, -261692320000000.0 as f32); // pass
let result = x.mul_add(y, z);
assert_eq!(result, -2489344.0 as f32); // fail
println!("x: {:>32b}, {}", x.to_bits(), x);
println!("y: {:>32b}, {}", y.to_bits(), y);
println!("z: {:>32b}, {}", z.to_bits(), z);
println!("result: {:>32b}, {}", result.to_bits(), result);

输出为

x:  1001011011110000101111011100000, 16277216
y:  1001011011101010101000110100000, 16077216
z: 11010111011011100000000111111110, -261692320000000
result: 11001010101111111010100000000000, -6280192

我有三个数字,它们使用(32位)浮点进行精确表示:

x = 16277216, y = 16077216, z = -261692320000000

这个前提是错误的-261692320000000无法以任何32位浮点格式精确表示,因为其有效位需要37位才能表示。

通常用于float的IEEE-754二进制32格式具有24位有效位。将−26169232000000的有效位缩放到224以下,大小为−2616923200000=−15598077.7740478515625•224。正如我们所看到的,有效位在这个尺度上不是整数,所以它不能精确地表示,我也不认为它是精确的。最接近的可表示值为−15598078•224=-26169323790848。

println!("z: {:>32b}, {}", z.to_bits(), z);

z:111010111011011100000000111111110,261692320000000

Rust在撒谎;则CCD_ 10的值不是CCD_。它可能使用了一些算法,如四舍五入到8位有效数字,其余部分使用零。z的实际值为−261692323790848。

使用普通实数算术的16277216•16077216−261692323790848的值为−6280192,因此FMA的结果是正确的。

舍入误差出现在let z = - x * y;中,其中16277216和16077216的乘积将261692317510656的实数算术结果舍入为二进制表示的最接近值322261692323790848。

相关内容

  • 没有找到相关文章

最新更新