使用 f64::mul_add 时如何引入额外的舍入误差?

How is additional rounding error introduced when using f64::mul_add?

提问人:Kelson Ball 提问时间:5/19/2018 最后编辑:ShepmasterKelson Ball 更新时间:5/19/2018 访问量:384

问:

根据文档,f64::mul_add 可用于减少舍入错误的机会:

pub fn mul_add(self, a: f64, b: f64) -> f64

融合乘加。仅使用一次舍入进行计算 错误。这将产生更准确的结果和更好的性能 而不是单独的乘法运算,后跟加法。(self * a) + b

我正在开发一个非常常见的线性变换库。当我引入结构的点积时,我失去了精度。a * b + ...mul_addAffineVector

这是点积法:

impl AffineVector {
    pub fn dot(self, v: AffineVector) -> f64 {
        self.x * v.x + self.y * v.y + self.z * v.z + self.w * v.w
        //  self.x.mul_add(v.x, self.y.mul_add(v.y, self.z.mul_add(v.z, self.w * v.w)))
    }
}

完整的来源在这里

在实现且没有其他更改的情况下,以下测试会失败,因为最后一个断言的浮点精度问题:mul_add

#[test]
fn inverse_rotation() {
    // create a rotation matrix for 1 radian about the Z axis
    let rotate = AffineMatrix::new(Primitives::RotationZ(1.));

    // create a matrix that undoes the rotation of 'rotate'
    let revert = rotate.inverse();

    // apply the transformation to the vector <1,0,0>
    let rotated = rotate.apply_vec3(KVector3::i_hat());        

    // assert that the result is <cos(1),sin(1),0>
    let expected = KVector3::new(C, S, 0.0);        
    assert_eq!(rotated, expected);

    // use the 'revert' matrix to undo the rotation
    let returned = revert.apply_vec3(rotated);     

    // assert that the result is back to <1,0,0>   
    assert_eq!(returned, KVector3::i_hat());
}
panicked at 'assertion failed: `(left == right)`   
left: `KVector3 { x: 1.0, y: 0.000000000000000023419586346110148, z: 0.0 }`,  
right: `KVector3 { x: 1.0, y: 0.0, z: 0.0 }`',

使用如何以及为什么会降低精度?我怎样才能有效地使用它?mul_add

防锈 浮动精度

评论

6赞 Shepmaster 5/19/2018
你为什么认为你“失去”了精确度?似乎更有可能的是,以前您有两个舍入错误,只是碰巧相互抵消。现在只有一个错误,你可以看到它。
0赞 Kelson Ball 5/19/2018
这种完美抵消所涉及的操作数量的四舍五入误差似乎极不可能
3赞 trent 5/19/2018
尽管如此,浮点计算是精确的案例很少,而这个测试似乎不是其中之一。如果你不期望相等,你不应该期望这个测试通过,除非是随机的偶然性。(如果你确实期望,你应该先阅读另一个问题0.1 + 0.20.30.1 + 0.2 == 0.3
5赞 Patricia Shanahan 5/19/2018
假设从左到右计算加法,重新编码改变了总和的顺序,这是改变舍入的高风险。
0赞 trent 5/23/2018
我建议将其作为浮点数学是否损坏的骗局关闭?当您进行更复杂的转换时,答案仍然适用。如果你真的在做一些浮点数学应该是精确的(只有二进制分数,没有舍入),那么这应该是问题所在。

答: 暂无答案