Способ RungeKutta в C, указатели и массивы


Теперь программа работает, но правильно ли это? Иногда это работает в C. Я могу его как-то улучшить (не численно, только c-мудрый)? Мне нужно передать массив, как мне правильно делать? Поскольку я возвращаю его, а не просто использовать его внутри функции.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/* Approximates a solution to a differential equation on the form: 
   y'(t) + ay(t) = x(t)
   y(0) = b 
*/
double* runge_kutta_2nd_order(double stepSize, double a, double b, double (*x) (double), double upto)
{
    int resultSize = ((int) (upto / stepSize)) + 2;
    double yt = b;
    double time;
    double k1,k2,ystar1,ystar2;
    int index = 1;

    //double *results = (double*) malloc(resultSize * (sizeof(double)));
    double *results = malloc(resultSize * sizeof(*results));
    if(results == NULL)
    {
        printf("\nCould not allocate memory. Exiting program.");
        exit(0);
    }

    results[0] = b;

    for(time = 0; time < upto; time += stepSize) //<=
    {   
        k1 = x(time) - a * yt;
        ystar1 = yt + stepSize * k1;
        k2 = x(time + stepSize) - a * ystar1;
        ystar2 = yt + (k1 + k2) / 2 * stepSize;
        yt = ystar2;
        results[index] = ystar2;
        index++;
    }
    return results;
}

void free_results(double **r)
{
    free(*r);
    *r = NULL;
}


double insignal(double t)
{
    return exp(t/2)*(sin(5*t) - 10*cos(5*t));
}

int main(void)
{
    int i;
    double *res = runge_kutta_2nd_order(0.01,-1,0,&insignal,10);


    printf("\nRunge Kutta 2nd order approximation of the differential equation:");
    printf("\ny'(t) - y(t) = e^(t/2) * (sin(5t) - 10cos(5t))");
    printf("\ny(0) = 0");
    printf("\n0 <= t <= 10");

    for(i=0; i<1001; i+=100){
        printf("\ni = %lf => y = ", 0.01*i);
        printf("%lf", res[i]);
    }
    printf("\n");

    free_results(&res);


    return 0;
}


1116
2
задан 4 декабря 2011 в 08:12 Источник Поделиться
Комментарии
1 ответ

Вообще, желательно поставить \пВ конце соответствующей функции printf, а не полагаться на их присутствие на следующим.

printf("\n"); // <-- you don't need to complicate your whole logic just because of this guy!
// put him on a line of his own.
printf("\y'(t) - y(t) = e^(t/2) * (sin(5t) - 10cos(5t))\n");
printf("\y(0) = 0\n");
printf("0 <= t <= 10\n");

for(i=0; i<1001; i+=100){
printf("i = %lf => y = %lf\n", 0.01*i, res[i]);
}

Кроме того, в качестве общего принципа я не хочу возвращения из malloc-Эд значений из функции, поскольку это


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

  2. пары свой алгоритм (численные расчеты) с управлением памятью. Было бы предпочтительнее, если бы Вы были свободны использовать любой тип памяти, а не принуждают с помощью malloc-бесплатно (как вы сейчас)

    Один из вариантов прохождения результирующего массива в качестве аргумента функции:

    //so you can malloc...
    double *result = malloc(/**/);
    runge_kutta( /*...*/, result);
    free(result);

    //...or not
    double results[MAX_SIZE];
    runge_kutta( /*...*/, result);

    Отметим, что в предыдущем примере теперь вы должны быть в состоянии знать длину результат заранее время. В большинстве случаев это банально, но в некоторых случаях вам может понадобиться упаковать это в подпрограмму.


Наконец, поскольку речь идет о ресурсоемких проблема и в списке результатов не нужны (так как я думаю, вы только должны смотреть на них по одному за раз и по порядку) вы, возможно, захотите рассмотреть вопрос о реорганизации вещей, так что вы можете уйти без каких-либо ассигнований на результаты выбора.

Например, мы могли бы иметь функцию Рунге Кутта вызвать обратного вызова в каждом результате он получает вместо сохранения в массив.

void runge_kutta_2nd_order(
/*the original arguments and...*/,
void (*onPoint)(int index, double x_i) /*the callback*/
)
{
//...
onPoint(index, ystar2);
//...
}

2
ответ дан 4 декабря 2011 в 09:12 Источник Поделиться