LinuxForum.Fans
Тема

[Решено] Какой-то глюк в C

Автор: Iced 9 сообщений 2567 просмотров 🔒 закрыта
#25884

Или я чего-то не понимаю, или что-то не так.
Итак, есть задача. Решить СЛУ (систему линейных уравнений) методом Гаусса (последовательного исключения переменных).
Задаю через текстовый файл два массива (один двумерный, главная матрица, и один одномерный).
Первый - это коэффициенты при x, а второй - свободные члены.

Допустим, уравнение вот такого вида:

text

a[0][0]x[0]+a[0][1]x[1]+...+a[0][n-1]x[n-1]=b[0]
...
a[n-1][0]x[0]+a[n-1]x[1]+...+a[n-1][n-1]x[n-1]=b[n-1]

Вот a - двумерный массив, b - одномерный.

Функция выглядит вот так:

text
double *gauss(int n, double **a, double *b) {
  int i,j,k;
  double minus;
  // строки i,j, столбцы k
  for (i=0; i!=n-1; i++) // исключаем переменную при a[i][i]
    for (j=i+1; j!=n; j++) { // из каждого уравения, начиная с a[j][k]
      for (k=0; k!=n; k++) { // для k-го столбца
        printf("a[%d][%d]=%lf\n",j,k,a[j][k]);
        minus=a[i][k]*a[j][i]/a[i][i];
        printf("minus=%lf\n",a[i][k]*a[j][i]/a[i][i]);
        /*a[j][k]=a[j][k]-minus;*/
        printf("a[%d][%d]=%lf\n",j,k,a[j][k]);
      }

b[i]-=a[i][k]*a[j][i]/a[i][i]; } for (i=0; i!=n; i++) { for (j=0; j!=n; j++) printf("%lf*x%d + ",a[i][j],j); printf("= %lf\n",b[i]); }

}

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

Так вот. Что меня просто заставило поделить на 0 много раз. :o :O oO :[
Если в таком виде - то выводит:

text
a[1][0]=4.000000
minus=4.000000
a[1][0]=4.000000
a[1][1]=5.000000
minus=8.000000
a[1][1]=5.000000
a[1][2]=6.000000
minus=12.000000
a[1][2]=6.000000
a[2][0]=7.000000
minus=7.000000
a[2][0]=7.000000
a[2][1]=3.000000
minus=14.000000
a[2][1]=3.000000
a[2][2]=1.000000
minus=21.000000
a[2][2]=1.000000
a[2][0]=7.000000
minus=2.400000
a[2][0]=7.000000
a[2][1]=3.000000
minus=3.000000
a[2][1]=3.000000
a[2][2]=1.000000
minus=3.600000
a[2][2]=1.000000
1.000000*x0 + 2.000000*x1 + 3.000000*x2 + = 4.000000
4.000000*x0 + 5.000000*x1 + 6.000000*x2 + = 3.000000
7.000000*x0 + 3.000000*x1 + 1.000000*x2 + = 2.000000

(ну это типа для отладки я сделал столько вывода.
Сначала пишется старое значение, потом сколько надо вычесть, а потом результат. Здесь просто закомментировано собственно вычитание, потому старое и новое значение совпадает.

Так вот, если раскомментировать строку

text
        /*a[j][k]=a[j][k]-minus;*/

которая собственно и занимается нужным мне вычитанием - то значение minus тоже меняется! и становится равным нулю везде, кроме первого столбца!!! Почему программа себя так ведёт? Ведь значение minus в этой строке меняться не должно! Или я чего-то неправильно понимаю?
Вот такой вывод:

text
a[1][0]=4.000000
minus=4.000000
a[1][0]=0.000000
a[1][1]=5.000000
minus=0.000000
a[1][1]=5.000000
a[1][2]=6.000000
minus=0.000000
a[1][2]=6.000000
a[2][0]=7.000000
minus=7.000000
a[2][0]=0.000000
a[2][1]=3.000000
minus=0.000000
a[2][1]=3.000000
a[2][2]=1.000000
minus=0.000000
a[2][2]=1.000000
a[2][0]=0.000000
minus=0.000000
a[2][0]=0.000000
a[2][1]=3.000000
minus=3.000000
a[2][1]=0.000000
a[2][2]=1.000000
minus=0.000000
a[2][2]=1.000000
1.000000*x0 + 2.000000*x1 + 3.000000*x2 + = 4.000000
0.000000*x0 + 5.000000*x1 + 6.000000*x2 + = 3.000000
0.000000*x0 + 0.000000*x1 + 1.000000*x2 + = 2.000000

Целиком исходник выглядит так:

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

double *gauss(int n, double **a, double *b) { int i,j,k; double minus; // строки i,j, столбцы k for (i=0; i!=n-1; i++) // исключаем переменную при a[i][i] for (j=i+1; j!=n; j++) { // из каждого уравения, начиная с a[j][k] for (k=0; k!=n; k++) { // для k-го столбца printf("a[%d][%d]=%lf\n",j,k,a[j][k]); minus=a[i][k]*a[j][i]/a[i][i]; printf("minus=%lf\n",a[i][k]*a[j][i]/a[i][i]); a[j][k]=a[j][k]-minus; printf("a[%d][%d]=%lf\n",j,k,a[j][k]); }

b[i]-=a[i][k]*a[j][i]/a[i][i]; } for (i=0; i!=n; i++) { for (j=0; j!=n; j++) printf("%lf*x%d + ",a[i][j],j); printf("= %lf\n",b[i]); }

}

int main(int argc, char *argv[]) { if (argc!=2) { printf("Введите ./kram matrix.txt\n"); return 0; } FILE *f=fopen(argv[1],"r"); if (!f) { printf("Файл не найден.\n"); return 0; } int n; fscanf(f,"%d",&n); int i,j; double **a; double *b; b=malloc(sizeof(double)*n); a=malloc(sizeof(double*)*n); for (i=0; i!=n; i++) { a[i]=malloc(sizeof(double)*n); for (j=0; j!=n; j++) fscanf(f,"%lf ",&a[i][j]); fscanf(f,"%lf\n",&b[i]); } double *x; x=gauss(n,a,b);

/*for (i=0; i!=n; i++) {*/ /*for (j=0; j!=n; j++)*/ /*printf("%lf*x%d + ",a[i][j],j);*/ /*printf("= %lf\n",b[i]);*/ /*}*/

/*for (i=0; i!=n; i++)*/ /*printf("x%d=%lf\n",i,x[i]);*/

fclose(f); /*for (i=0; i!=n; i++) free(a[i]);*/ /*free(a);*/ return 0; }

#25964
Flaming написал:
text
minus=a[i][k]*a[j][i]/a[i][i];

вроде всё нормально...
попробуйте пробелов поставить:

text
X_=_Y_*_Z_/_T;
#25965
Flaming написал:
Или я чего-то не понимаю, или что-то не так.
...
Целиком исходник выглядит так:
text
#include <stdio.h>
#include <stdlib.h>

double *gauss(int n, double **a, double *b) { int i,j,k; double minus; // строки i,j, столбцы k for (i=0; i!=n-1; i++) // исключаем переменную при a[i][i] for (j=i+1; j!=n; j++) { // из каждого уравения, начиная с a[j][k] for (k=0; k!=n; k++) { // для k-го столбца printf("a[%d][%d]=%lf\n",j,k,a[j][k]); minus=a[i][k]*a[j][i]/a[i][i]; printf("minus=%lf\n",a[i][k]*a[j][i]/a[i][i]); a[j][k]=a[j][k]-minus; printf("a[%d][%d]=%lf\n",j,k,a[j][k]); }

b[i]-=a[i][k]*a[j][i]/a[i][i]; } for (i=0; i!=n; i++) { for (j=0; j!=n; j++) printf("%lf*x%d + ",a[i][j],j); printf("= %lf\n",b[i]); }

}

int main(int argc, char *argv[]) { if (argc!=2) { printf("Введите ./kram matrix.txt\n"); return 0; } FILE *f=fopen(argv[1],"r"); if (!f) { printf("Файл не найден.\n"); return 0; } int n; fscanf(f,"%d",&n); int i,j; double **a; double *b; b=malloc(sizeof(double)*n); a=malloc(sizeof(double*)*n); for (i=0; i!=n; i++) { a[i]=malloc(sizeof(double)*n); for (j=0; j!=n; j++) fscanf(f,"%lf ",&a[i][j]); fscanf(f,"%lf\n",&b[i]); } double *x; x=gauss(n,a,b);

/*for (i=0; i!=n; i++) {*/ /*for (j=0; j!=n; j++)*/ /*printf("%lf*x%d + ",a[i][j],j);*/ /*printf("= %lf\n",b[i]);*/ /*}*/

/*for (i=0; i!=n; i++)*/ /*printf("x%d=%lf\n",i,x[i]);*/

fclose(f); /*for (i=0; i!=n; i++) free(a[i]);*/ /*free(a);*/ return 0; }

double a[n][m] = malloc(sizeof(double)*n*m); /* Вот отсюда и исходите */

#26005

// Гусс на си, какой кошмар T_T

i = 0; j = 1;

text

      for (k=0; k!=n; k++) { // для k-го столбца
           minus=a[i][k]*a[j][i]/a[i][i];
        /*a[j][k]=a[j][k]-minus;*/
      }

Если снять коммент, то при k=0 a[1][0] обращается в нуль. потом k=1: minus = a[0][1]*a[1][0]/a[0][0] etc.

ку?

#26026

Marvin, ничего не поделаешь :) именно так и задали сделать.
В принципе, вполне реально, просто муторно.

Думаете, матрицу двумерную я выделил неправильно? Выделял так же, как для метода Крамера. Кстати, он работает - могу выложить исходник. :)

#26029

Flaming, я вроде написал, почему minus стал нулём, нэ?

#26049

Marvin, я не увидел. :) где?

text
printf("a[%d][%d]=%lf\n",j,k,a[j][k]);
minus=a[i][k]*a[j][i]/a[i][i];
printf("minus=%lf\n",a[i][k]*a[j][i]/a[i][i]);
/*a[j][k]=a[j][k]-minus;*/
printf("a[%d][%d]=%lf\n",j,k,a[j][k]);

При таком раскладе minus не равен нулю везде, кроме первого столбца.

А если вот так

text
printf("a[%d][%d]=%lf\n",j,k,a[j][k]);
minus=a[i][k]*a[j][i]/a[i][i];
printf("minus=%lf\n",a[i][k]*a[j][i]/a[i][i]);
a[j][k]=a[j][k]-minus;
printf("a[%d][%d]=%lf\n",j,k,a[j][k]);

То везде 0. Почему? :(

#26065

Гм. Может я чего не так понял. Давай посмотрим, тупо раскрыв твои for'ы

text

i = 0; j = 1; k=0: minus=a[0][0]*a[1][0]/a[0][0]; <-- очевидно, minus=a[1][0] a[1][o]=a[1][0] - minus; <-- не менее очевидно это делает a[1][0] нулём.

k=1: minus = a[0][1]*a[1][0]/a[0][0] а a[1][0] совсем недавно стал нулём! a[1][1] = a[1]*a[1] - 0;

k = 2: minus = a[0][2]*a[1][0]/a[0][0] <--- ч0рт! Снова нуль!

с Си всё нормально, minus нуль. Нэ?

#26071

Ладно, попробую сегодня-завтра на свежую голову этот фрагмент с нуля написать. :) Обычно так лучше получается.
Чувствую, с индексами i,j,k перемудрил, или где-то перепутал их местами. Сейчас поменял - стало только хуже.

Marvin, спасибо. :) Понял. Поправил.
Теперь minus у меня присваивается не при каждой итерации цикла, а один раз, и сохраняется. И теперь всё работает как надо.

Если кому надо - исходники могу кинуть. ;)

Войдите или зарегистрируйтесь, чтобы ответить.