-1

这是物理引擎中的一部分。
简化函数centerOfMass计算两个刚体的一维质心(演示):-

#include <iostream>
#include <iomanip> 
float centerOfMass(float pos1,float m1, float pos2,float m2){
    return (pos1*m1+pos2*m2)/(m1+m2);
}
int main(){
    float a=5.55709743f;
    float b= centerOfMass(a,50,0,0);
    std::cout << std::setprecision(9) << a << '\n';  //5.55709743
    std::cout << std::setprecision(9) << b << '\n';  //5.55709696
}

我需要b精确 = 5.55709743。

有时(我的真实情况= 5%)微小的差异会引入令人讨厌的物理分歧。
有一些方法可以解决它,例如大量进行一些条件检查。
但是,这对我来说非常容易出错。

问题:如何解决计算错误,同时保持代码干净、快速、易于维护?

顺便说一句,如果不能优雅地完成,我可能需要改进调用者以更能抵抗这种数字错误。

编辑

(澄清重复的问题)

是的,原因是存储/计算格式的精度错误(在Is floating point math broken?中提到)。

但是,这个问题询问如何在非常具体的情况下 消除其症状。

4

2 回答 2

2

您试图获得 9 位小数的精度,但数据类型float精度约为 7 位小数

改用double. _ 演示

于 2018-01-21T04:15:33.967 回答
1

使用双精度,而不是浮点数。IEEE 754 双精度大约有 16 位小数。

#include <iostream>
#include <iomanip> 
double centerOfMass(double pos1, double m1, double pos2, double m2) {
    return (pos1*m1 + pos2 * m2) / (m1 + m2);
}
int main() {
    double a = 5.55709743;
    double b = centerOfMass(a, 50, 0, 0);
    std::cout << std::setprecision(16) << a << '\n';  //5.55709743
    std::cout << std::setprecision(16) << b << '\n';  //5.55709743
    std::cout << std::setprecision(16) << (b - a) << '\n';  // 0
}

对于给出的示例 centerOfMass(a, 50, 0, 0),以下将给出所有 a 值的准确结果,但当然该示例看起来并不现实。

double centerOfMass(double pos1, double m1, double pos2, double m2) {
    double divisor = m1 + m2;
    return pos1*(m1/divisor) + pos2*(m2/ divisor);
}
于 2018-01-21T07:50:59.127 回答