Вот часть физического движка.
Упрощенная функция 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%), вносит неприятное расхождение в физике.
Есть несколько способов решить это, например. сильно сделать некоторую условную проверку.
Тем не менее, это очень подвержено ошибкам для меня.
Вопрос: Как устранить ошибку в вычислениях, сохранив код чистым, быстрым и легким в обслуживании?
Между прочим, если это не может быть сделано элегантно, мне, вероятно, нужно улучшить вызывающую функцию, чтобы быть более устойчивой к такой числовой ошибке.
(уточнить дублирующий вопрос)
Да, причиной является ошибка точности в формате хранения / вычисления (упоминается в Математика с плавающей точкой нарушена?).
Тем не менее, этот вопрос спрашивает о том, как нейтрализовать его симптом в очень конкретном случае.
Вы пытаетесь получить 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);
}