Небольшая числовая ошибка при расчете среднего веса

Вот часть физического движка.
Упрощенная функция centerOfMass вычисляет 1D-центр масс двух твердых тел ( демо):-

#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%), вносит неприятное расхождение в физике.
Есть несколько способов ее решить, например, выполнить некоторую условную проверку.
Тем не менее, это очень подвержено ошибкам для меня.

Вопрос: Как устранить ошибку в вычислениях, сохранив код чистым, быстрым и легким в обслуживании?

Между прочим, если это не может быть сделано элегантно, мне, вероятно, нужно улучшить вызывающую функцию, чтобы быть более устойчивой к такой числовой ошибке.

редактировать

(уточнить дублирующий вопрос)

Да, причина кроется в ошибке точности в формате хранения / вычисления (упоминается в разделе " Не работает ли математика с плавающей запятой?").

Однако этот вопрос задает вопрос о том, как нейтрализовать его симптом в очень конкретном случае.

2 ответа

Вы пытаетесь получить 9 десятичных знаков точности, но тип данных float имеет точность около 7 десятичных цифр.

использование double вместо. ( демо)

Используйте двойной, а не плавать. IEEE 754 double имеет около 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);
}
Другие вопросы по тегам