Эффективный расчет положения, скорости и других производных движения объекта

Хорошо, вот головоломка программирования/физики, скажем, на Java (хотя это не имеет большого значения, но для согласованности мы будем использовать Java).

У меня есть массив двойников, где каждый элемент представляет последовательные производные позиции объекта. Так:

d[0] // position
d[1] // velocity
d[2] // accelleration

так далее ...

Будет как минимум 1 и потенциально любое количество элементов (но на практике, вероятно, не более 5). Все элементы за пределами конца массива считаются равными нулю.

У нас также есть double t для времени.

Итак, если бы d.length было 3, то очень конкретно:

d[0] += d[1] * t + d[2] * t * t / 2
d[1] += d[2] * t

Но как написать итеративное решение (без рекурсии!), которое будет обновлять все элементы массива за время t для любой длины a?

Голоса должны быть присуждены за эффективность и лаконичность.

РЕДАКТИРОВАТЬ: Законы движения находятся на страницах физики этого сайта, но в основном каждый термин имеет форму:

power(t,n) / factorial(n)

Таким образом, следующий член первого уравнения будет d[3] * t*t*t / 6

Если вы не знакомы с этими уравнениями, пожалуйста, не просите меня объяснить.

Тестовый пример:

final static double[] D = { 5.0, 4.0, 3.0, 2.0, 1.0 };
double t = 10.0

должен дать:

[945.0, 300.66666666666663, 73.0, 12.0, 1.0]

Второй элемент может отличаться из-за ошибок точности.


person rghome    schedule 20.03.2015    source источник
comment
Пожалуйста, не могли бы вы обновить свой вопрос, показав пример с a.length == 3?   -  person davidbuzatto    schedule 21.03.2015
comment
Так спрашиваешь про схему интеграции? у вас есть фиксированный шаг времени?   -  person MinaKamel    schedule 21.03.2015
comment
Должно было быть length == 3. Измените имя массива на d, чтобы не путать его с ускорением. t явно не фиксируется.   -  person rghome    schedule 21.03.2015
comment
Спасибо за ответы. Я собираюсь оставить его открытым на некоторое время, чтобы посмотреть, не появится ли что-нибудь действительно интересное.   -  person rghome    schedule 21.03.2015


Ответы (2)


Я думаю, что-то вроде этого работает.

int length = d.length;
for (int i = 0; i < length - 1; i++) {
    double temp = 0;
    for (int j = length - 1; j > i; j--)
        temp = (temp + d[j]) * t / (j - i);
    d[i] += temp;
}
person Paul Boddington    schedule 20.03.2015
comment
Это дает несколько худшие ошибки округления, чем другие решения: [945.0, 300.66666666666674, 73.0, 12.0, 1.0] - person rghome; 21.03.2015
comment
@rghome Да, подойдет. Чтобы точно вычислить степени, подобные t * t * t * t * t, нужно использовать Math.pow (поскольку каждое последующее умножение вносит новую ошибку). Поэтому, если вам нужна точность, вы фактически не можете повторно использовать ранее рассчитанные ответы для t, t * t, t * t * t, t * t * t * t. Если вам нужна точность, я не думаю, что вы можете добиться большего успеха, чем вычислить каждый из t, t * t / 2, t * t * t / 6 с нуля, но я могу ошибаться. - person Paul Boddington; 21.03.2015
comment
Я получил меньшие ошибки округления, сначала выполняя деление, но, возможно, это будет зависеть от тестового примера. - person rghome; 21.03.2015

Обновлено:

for (int i = 0; i < d.length - 1; i++) {
    d[i] = 0;
    int f = 1;
    double p = 1;
    for (int j = i+1; j < d.length; j++) {
        f *= j - i;
        p *= t;
        d[i] += d[j] * p / f;
    }
}
person axblount    schedule 20.03.2015
comment
Проголосуйте за первый ответ, но я считаю, что можно избежать пересчета факториала и мощности, по крайней мере, во внутреннем цикле. Может быть, даже во внешнем цикле. - person rghome; 21.03.2015