Исключение с плавающей точкой в ​​коде C! - PullRequest
4 голосов
/ 26 апреля 2010
#include<stdio.h>
#include<math.h>

int main ()
{
    FILE *fp;
    fp=fopen("output","w");
    float t,y=0,x=0,e=5,f=1,w=1;
    for (t=0;t<10;t=t+0.01)
    {
        if( y==inf && y== nan) 
            break;
        fprintf(fp,"%lf\t%lf\n",y,x);
        y = y + ((e*(1 - x*x)*y) - x + f*cos(w*t))*t;
        x = x + y*t;
    }
    return 0;
}

Почему выходной сигнал дает бесконечные значения и значения NAN?

Ответы [ 8 ]

8 голосов
/ 26 апреля 2010

Ваш расчет взрывается. Просто посмотрите на значения, напечатанные для x и y, и вы увидите, что они начинают становиться очень большими, а затем включите информацию inf. Поскольку ваше условие неверно, вы используете inf в расчете, который превращается в nan.

6 голосов
/ 26 апреля 2010

Сравнение с inf или nan выполняется с помощью функций isnan() и isinf(), но не так.
%lf для double, а не float.

И, ради бога, fclose() ваш файл! (первые X строк - это несколько значащих чисел.)

4 голосов
/ 26 апреля 2010

Другие отметили, что у вас проблемы с nan / inf, и это правда, но вот как исправить ваш код, чтобы получить результаты, которые, я полагаю, вы ищете.

Поскольку никто больше не указал на это (что я заметил), вы пытаетесь решить систему дифференциальных уравнений, используя метод Эйлера . Связанные дифференциальные уравнения, которые вы решаете:

dy/dt = e*(1 - x * x) * y - x + f * cos(w * t)

dx/dt = y

Однако ваше решение неверно, что дает огромную числовую нестабильность (и неправильный ответ). Эти две строки:

    y = y + ((e*(1 - x*x)*y) - x + f*cos(w*t))*t;
    x = x + y*t;

должно быть:

    y = y + ((e*(1 - x*x)*y) - x + f*cos(w*t))*.01;
    x = x + y*.01;

где я изменил t на вашу дельту t (шаг по времени), потому что это то, что требует метод Эйлера. Я бы сделал новую переменную с именем delt или что-то в этом роде, чтобы вы могли легко изменить временной шаг. Решение теперь прекрасно стабильно, и построение графиков x против t и y против t дает очень хорошие графики. Я бы опубликовал их, но у меня есть ощущение, что это может быть домашнее задание.

Кроме того, если с другими уравнениями вам нужна большая стабильность, вы можете использовать меньшие временные шаги или некоторые лучшие численные методы ОДУ, такие как Рунге-Кутта или неявные методы.

3 голосов
/ 26 апреля 2010

Имейте в виду, что каждое сравнение с использованием NaN возвращает false независимо от того, какой оператор вы используете (<, <= и т. Д.) И с чем вы сравниваете его. </p>

3 голосов
/ 26 апреля 2010

Возможно, условное утверждение должно быть, если (y == inf || y == nan)? y не может быть одновременно inf и NaN.

1 голос
/ 26 апреля 2010

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

0 голосов
/ 26 апреля 2010

Среди других проблем, которые были рассмотрены другими, условный разрыв никогда не сработает. y == nan ложно для каждого значения y, включая NaN, поэтому условие равно (y == inf && false), что, конечно, false.

Если вы хотите разорвать, когда y равен inf или nan, вы должны использовать:

if (isinf(y) || isnan(y)) break;

Или, если вы хотите использовать сравнения вместо:

if (fabs(y) == inf || y != y) break;

(Фабы включены, потому что вы - предположительно - тоже хотите сломаться, если y равен -inf.)

0 голосов
/ 26 апреля 2010

Я подключил ваши уравнения в Excel, и когда t достигает 0,39 x, а y равны 2E + 270 и 5,2E + 270 соответственно. После этого они слишком велики для Excel. Вот след других значений, если вам интересно (паршивое форматирование, я знаю):

t   x       y
0.00    0       0
0.01    9.9995E-05  0.0099995
0.02    0.000719864 0.03099345
0.03    0.002688085 0.065607372
0.04    0.007431658 0.118589309
0.05    0.017321769 0.197802239
0.06    0.036281294 0.315992075
0.07    0.070850729 0.493849065
0.08    0.132072044 0.765266446
0.09    0.238828626 1.186184238
0.10    0.423641428 1.848128022
0.11    0.741634646 2.89084744
0.12    1.277397835 4.464693237
0.13    2.107123319 6.382503724
0.14    3.048840735 6.726552977
0.15    3.361369798 2.083527082
0.16    3.297988472 -0.396133288
0.17    3.231095608 -0.393487431
0.18    3.156811159 -0.412691383
0.19    3.07386543  -0.436556472
0.20    2.980485636 -0.466898968
0.21    2.874086586 -0.506662146
0.22    2.750700903 -0.56084401
0.23    2.603841953 -0.638517177
0.24    2.42203123  -0.757544679
0.25    2.18283838  -0.9567714
0.26    1.836632623 -1.331560601
0.27    1.255566799 -2.152095647
0.28    0.052253914 -4.297546016
0.29    -2.923971917    -10.2628477
0.30    -2.375067218    1.82968233
0.31    -1.600801299    2.497631996
0.32    0.082957072 5.261744912
0.33    4.774399642 14.21649263
0.34    -20.07952886    -73.09978971
0.35    3522.569432 10121.85417
0.36    -16277355468    -45214886085
0.37    1.64003E+30 4.43252E+30
0.38    -1.72156E+90    -4.53043E+90
0.39    2.0423E+270 5.2366E+270
0.40    #NUM!       #NUM!

Так что, я думаю, вопрос в том, что этот код должен вычислять?

...