Javascript точность снижения
Я понимаю, что ошибки округления javascript довольно трудно исправить, но я хотел бы получить совет.
Как лучше всего исправить ошибки округления для моего приложения? У меня есть куб, на котором ДОЛЖНА быть орбита вокруг большой массы. Куб набирает значительную часть орбитального импульса на каждой орбите и в конечном итоге достигнет скорости убегания без какого-либо вмешательства.
Мне нужен легкий метод, чтобы предотвратить это.
Является ли моя лучшая ставка, чтобы попытаться найти способ исправить мои числа, или мне лучше использовать исправление ошибок, основанное на логическом предположении о том, где следует сортировать данные и возвращать их обратно на место?
Функции для моей физики здесь:
function physPosition(object, delta){
// Update Position
object.position.x += (object.velocity.x * delta) + (0.5*object.acceleration.x* (Math.pow(delta,2)));
object.position.y += (object.velocity.y * delta) + (0.5*object.acceleration.y*(Math.pow(delta,2)));
object.position.z += (object.velocity.z * delta) + (0.5*object.acceleration.z*(Math.pow(delta,2)));
// Update Velocity (acceleration)
object.velocity.x += object.acceleration.x * delta;
object.velocity.y += object.acceleration.y * delta;
object.velocity.z += object.acceleration.z * delta;
// Update Velocity (gravity)
object.velocity.x += object.gravity.x * delta;
object.velocity.y += object.gravity.y * delta;
object.velocity.z += object.gravity.z * delta;
// Update Rotation
object.rotation.x += object.spin.x * delta;
object.rotation.y += object.spin.y * delta;
object.rotation.z += object.spin.z * delta;
}
function physGravity(a, b){
var grav = new THREE.Vector3(0, 0, 0);
grav = grav.subVectors(a.position, b.position);
var r = grav.lengthSq();
var A = (G)*(b.mass)/(r);
grav = grav.normalize();
grav.multiplyScalar(-A);
a.gravity = grav;
}
2 ответа
Вы пытаетесь выполнить численное интегрирование уравнений движения. Это одно правильное решение - другое - вычислить аналитическое решение уравнений движения, как это предложил Дерек. Дело в том, что вам нужен лучший интегратор, чем решение, которое вы используете сейчас. Вы должны попытаться узнать о численной интеграции. В частности, я бы порекомендовал методы Рунге-Кутты, так как они просты в реализации и использовании.
Вы также можете найти библиотеку JavaScript, которая содержит методы численной интеграции, и использовать их, а не реализовывать свои собственные. Здесь приведен пример с методом Рунге-Кутты четвертого порядка, а библиотека Numeric JavaScript содержит интегратор Dormand-Prince, который называется dopri
,
В то время как комментарий Дерека имеет смысл - сделайте все функции параметрическими, если можете, а не дифференциальными - иногда вы не можете сделать это по-настоящему или не так просто. С вашим кодом другая возможность (не уверен, насколько реалистична) состоит в том, чтобы попытаться уменьшить ошибку, используя дроби самостоятельно, вместо того, чтобы полагаться на арифметику с плавающей запятой, поскольку у вас нет формул, которые враждебны дробям (например, квадратные корни),
Реализуйте свою собственную арифметику дроби, всегда сохраняя числитель и знаменатель разделенными, и делите их только тогда, когда это абсолютно необходимо для вычисления координат точки. Это должно: повысить точность, поскольку у вас есть удвоенное количество доступных битов; Кроме того, ошибка с плавающей запятой происходит в основном из-за того, что не может быть представлено в базе 2, но у вас будет столько целых чисел, сколько позволит JavaScript. Вам может понадобиться время от времени нормализовать числитель и знаменатель, так как они угрожают выйти за пределы диапазона, что приведет к некоторой ошибке, но реже, чем при каждом делении, как вы делаете с простой арифметикой с плавающей запятой.
Очевидно, это также замедлит вас, но JavaScript довольно быстр в расчете.