Согласно документам, f64::mul_add
может использоваться для уменьшения количества возможностей для ошибок округления:
pub fn mul_add(self, a: f64, b: f64) -> f64
Слияние, умножение, сложение.Вычисляет (self * a) + b
только с одной ошибкой округления.Это дает более точный результат с лучшей производительностью, чем отдельная операция умножения с последующим добавлением.
Я работаю над библиотекой линейных преобразований, где a * b + ...
очень распространено.Когда я ввел mul_add
для точечных продуктов моей AffineVector
struct I потерянной точности.
Это метод точечных произведений:
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
снизило точность?Как я могу использовать это эффективно?