質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.40%

  • C

    4131questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語 行列のファイル読み込み(と、ガウス消去法計算)

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 2,060

ISARIA

score 18

大学の課題で、コンパイルは通ったのですが、うまく読み込んでいないようです。

ガウス消去法を用いて Ax = B を x について解くというもので、行列Aと行列Bはそれぞれ.csvファイルに保存されています。
行列Aはコマンドライン関数として、行列Bはプログラム内で読み込むことがそれぞれ指定されています。
プログラムを実行してみると、行列A,B共に1列目の数字を読み込んだ際に値が変わってしまっているようです。その原因がどこにあるのかがわからずに困っています。
行列Aは4行4列の以下のようなもので、
{3.1    -5.3    3.8    -3.8}
{4.1    5.9    4.6    3.2}
{-5.9    7.9    -2.6    7.9}
{2.6    -3.2    -4.3    -5}
行列Bは1行4列の以下のようなものです。
{3}
{2}
{5}
{-1}
原因を教えていただけないでしょうか。よろしくお願いします!!
以下にプログラムと実行結果を載せます。

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <math.h>
#define N 4    
#define EPS 1e-6
typedef double Matrix[N][N+1];


//行列を読み込む関数
void scan_data1(FILE* ifp, Matrix a)
{
    int num[N] = { 0 };        //列の数を数える
    for (int i = 0; i<N; i++) {
        for (int j = 0; j<N + 1; j++) {
            char data = 0;        //文字を読み込むための
            fscanf(ifp, "%c", &data);
            if (data == '\n') {        //改行していたら、ループを抜ける。
                break;
            }
            else if (data == '\0') {        //読み込みが終了したら、ループを抜ける。
                break;
            }
            fscanf(ifp, "%lf", &a[i][j]);        //数値を読み込む
        }
    }
}

void scan_data2(FILE* ifp, Matrix a)
{
    for (int i = 0; i < N; i++) {
        char data = 0;        //文字を読み込むための
        fscanf(ifp, "%c", &data);
        if (data == '\n') {        //改行していたら、ループを抜ける。
            break;
        }
        else if (data == '\0') {        //読み込みが終了したら、ループを抜ける。
            break;
        }
        fscanf(ifp, "%lf", &a[i][N]);        //数値を読み込む
    }
}

//行列を表示する
void print_matrix(Matrix a)
{
    for (int i = 0; i<N; i++) {
        for (int j = 0; j<N; j++) {
            printf("%8.3f ", a[i][j]);
        }
        printf("| %8.3f\n", a[i][N]);
    }
    printf("\n");
}

void change_low(Matrix a, int i)
{
    int k = i;    //最大となる行
    double max_value = fabs(a[i][i]);

    for (int j = i + 1; j<N; j++) {
        if (max_value<fabs(a[j][i])) {
            k = j;
            max_value = fabs(a[j][i]);
        }
    }
    if (max_value == fabs(a[i][i])) {        //入れ替えがなかったら
        printf("====     No change!!      ====\n\n");
    }
    else {
        for (int j = 0; j<N + 1; j++) {
            double tmp = a[i][j];
            a[i][j] = a[k][j];
            a[k][j] = tmp;
        }
        printf("====  change!! low:%d low:%d    ====\n\n", i + 1, k + 1);
        print_matrix(a);
    }
}

void forward_elimination(Matrix a)
{
    //前進消去
    printf("====Foward elimination====\n");
    for (int i = 0; i<N; i++) {
        change_low(a, i);
        double pivot = a[i][i];        //ピボット

        for (int j = i; j<N + 1; j++)
            a[i][j] /= pivot;

        //掃き出し計算
        for (int k = i + 1; k<N; k++) {
            if (k != i) {
                double d = a[k][i];
                for (int j = i; j<N + 1; j++)    //k行目をすべて揃えている
                    a[k][j] -= d*a[i][j] / a[i][i];
            }
        }
        print_matrix(a);
    }
}

void backward_substitution(Matrix a)
{
    //後退代入
    printf("====Back substitution====\n");
    for (int i = N - 1; i >= 0; i--) {
        for (int j = i + 1; j < N; j++) {
            a[i][N] -= a[i][j] * a[j][N];
            a[i][j] = 0;
        }
        a[i][N] = a[i][N] / a[i][i];
        print_matrix(a);
    }
}

// ガウス消去法を使って連立方程式を解く
void gauss_elimination(Matrix a)
{
    forward_elimination(a);
    backward_substitution(a);
}

//計算結果を表示する
void print_result(Matrix a)
{
    printf("====results====\n");
    for (int i = 0; i<N; i++) {
        printf(" x%d = %9.3lf\n", i + 1, a[i][N]);
    }
}

int main(int argc, char* argv[])
{
    FILE* ifp1 = NULL;  //入力用ファイルポインタ
    char* ifile1 = NULL;   //入力ファイル名
    ifile1 = argv[1];  //パラメータの1番目を入力ファイル名

    /*コマンドライン関数で読み込んだファイルを開く*/
    if (argc != 2) {   //実行時引数が1個なかったらエラーとする
        fprintf(stderr, "usage: %s inputfile outputfile\n", argv[0]);
        exit(1);
    }
    if ((ifp1 = fopen(ifile1, "rt")) == NULL) { //入力ファイルを開く
        fprintf(stderr, "Can't open file %s\a\n", ifile1); //開けなかったら終了
        exit(2);
    }

    /*解の書き込まれているファイルを開く。*/
    FILE* ifp2 = NULL;
    char* ifile2 = "b_vec.csv";
    if ((ifp2 = fopen(ifile2, "rt")) == NULL) { //入力ファイルを開く
        fprintf(stderr, "Can't open file %s\a\n", ifile2); //開けなかったら終了
        exit(3);
    }

    Matrix A = { 0 };

    scan_data1(ifp1, A);
    print_matrix(A);        //ファイルA確認
    scan_data2(ifp2, A);

    print_matrix(A);        //ファイルAB確認
    gauss_elimination(A);
    print_result(A);

    fclose(ifp1);   //ファイルを閉じる
    fclose(ifp2);

    return (0);
}
   0.100   -5.300    3.800   -3.800 |    0.000
   0.100    5.900    4.600    3.200 |    0.000
   5.900    7.900   -2.600    7.900 |    0.000
   0.600   -3.200   -4.300   -5.000 |    0.000

   0.100   -5.300    3.800   -3.800 |    2.000
   0.100    5.900    4.600    3.200 |    0.000
   5.900    7.900   -2.600    7.900 |    0.000
   0.600   -3.200   -4.300   -5.000 |    0.000

====Foward elimination====
====  change!! low:1 low:3      ====

   5.900    7.900   -2.600    7.900 |    0.000
   0.100    5.900    4.600    3.200 |    0.000
   0.100   -5.300    3.800   -3.800 |    2.000
   0.600   -3.200   -4.300   -5.000 |    0.000

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    5.766    4.644    3.066 |    0.000
   0.000   -5.434    3.844   -3.934 |    2.000
   0.000   -4.003   -4.036   -5.803 |    0.000

====     No change!!    ====

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.805    0.532 |    0.000
   0.000    0.000    8.221   -1.044 |    2.000
   0.000    0.000   -0.811   -3.675 |    0.000

====     No change!!    ====

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.805    0.532 |    0.000
   0.000    0.000    1.000   -0.127 |    0.243
   0.000    0.000    0.000   -3.778 |    0.197

====     No change!!    ====

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.805    0.532 |    0.000
   0.000    0.000    1.000   -0.127 |    0.243
   0.000    0.000    0.000    1.000 |   -0.052

====Back substitution====
   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.805    0.532 |    0.000
   0.000    0.000    1.000   -0.127 |    0.243
   0.000    0.000    0.000    1.000 |   -0.052

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.805    0.532 |    0.000
   0.000    0.000    1.000    0.000 |    0.237
   0.000    0.000    0.000    1.000 |   -0.052

   1.000    1.339   -0.441    1.339 |    0.000
   0.000    1.000    0.000    0.000 |   -0.163
   0.000    0.000    1.000    0.000 |    0.237
   0.000    0.000    0.000    1.000 |   -0.052

   1.000    0.000    0.000    0.000 |    0.392
   0.000    1.000    0.000    0.000 |   -0.163
   0.000    0.000    1.000    0.000 |    0.237
   0.000    0.000    0.000    1.000 |   -0.052

====results====
 x1 =     0.392
 x2 =    -0.163
 x3 =     0.237
 x4 =    -0.052
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

ファイルからの読み込みで最初に1文字読み込んで、改行・EOFではなかったら数値として読み込もうとしているようですが、そうすると読み込むたびにファイルポインタが進み、数値を読み込むときには1文字ずれたところを読み込むことになります。
つまり3.1のところは、
最初のfscanfで3、次のfscanfで.1を処理していることになります。
1文字ずつ処理するのではなく、fscanfで1行まとめて処理してはどうでしょうか。

fscanf("%lf %lf %lf %lf", &a[i][0], &a[i][1], &a[i][2], &a[i][3]);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/09 14:39

    ポインタの考え方が間違っていたようです。
    本当にありがとうございます!

    キャンセル

0

        char data = 0;        //文字を読み込むための
        fscanf(ifp, "%c", &data);
        if (data == '\n') {        //改行していたら、ループを抜ける。
            break;
        }
        else if (data == '\0') {        //読み込みが終了したら、ループを抜ける。
            break;
        }
        fscanf(ifp, "%lf", &a[i][N]);        //数値を読み込む

これだと例えば「3.1」を読もうとした際、

  1. 最初のfscanfで3を読む
  2. 改行や終端じゃないので続ける
  3. 次のfscanfで.1を読む

と、各行の最初の1文字は捨てられます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/09 14:39

    ありがとうございます!

    キャンセル

0

行列Aのデータ{}付でファイルを作成しました。{}前後に空白無です。
{3.1    -5.3    3.8    -3.8}
{4.1    5.9    4.6    3.2}
{-5.9    7.9    -2.6    7.9}
{2.6    -3.2    -4.3    -5}
行列Bのデータも同様です。
{3}
{2}
{5}
{-1}

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <math.h>
#define N 4
#define EPS 1e-6
typedef double Matrix[N][N+1];


//行列を読み込む関数
void scan_data1(FILE* ifp, Matrix a)
{
    int num[N] = { 0 };        //列の数を数える
    for (int i = 0; i<N; i++) {
        fscanf(ifp, "%*1c%lf%lf%lf%lf%*2c", &a[i][0],&a[i][1],&a[i][2],&a[i][3]);        //数値を読み込む
    }
}

void scan_data2(FILE* ifp, Matrix a)
{
    for (int i = 0; i < N; i++) {
        fscanf(ifp, "%*1c%lf%*2c", &a[i][N]);        //数値を読み込む
    }
}

//行列を表示する
void print_matrix(Matrix a)
{
    for (int i = 0; i<N; i++) {
        for (int j = 0; j<N; j++) {
            printf("%8.3f ", a[i][j]);
        }
        printf("| %8.3f\n", a[i][N]);
    }
    printf("\n");
}

void change_low(Matrix a, int i)
{
    int k = i;    //最大となる行
    double max_value = fabs(a[i][i]);

    for (int j = i + 1; j<N; j++) {
        if (max_value<fabs(a[j][i])) {
            k = j;
            max_value = fabs(a[j][i]);
        }
    }
    if (max_value == fabs(a[i][i])) {        //入れ替えがなかったら
        printf("====     No change!!      ====\n\n");
    }
    else {
        for (int j = 0; j<N + 1; j++) {
            double tmp = a[i][j];
            a[i][j] = a[k][j];
            a[k][j] = tmp;
        }
        printf("====  change!! low:%d low:%d    ====\n\n", i + 1, k + 1);
        print_matrix(a);
    }
}

void forward_elimination(Matrix a)
{
    //前進消去
    printf("====Foward elimination====\n");
    for (int i = 0; i<N; i++) {
        change_low(a, i);
        double pivot = a[i][i];        //ピボット

        for (int j = i; j<N + 1; j++)
            a[i][j] /= pivot;

        //掃き出し計算
        for (int k = i + 1; k<N; k++) {
            if (k != i) {
                double d = a[k][i];
                for (int j = i; j<N + 1; j++)    //k行目をすべて揃えている
                    a[k][j] -= d*a[i][j] / a[i][i];
            }
        }
        print_matrix(a);
    }
}

void backward_substitution(Matrix a)
{
    //後退代入
    printf("====Back substitution====\n");
    for (int i = N - 1; i >= 0; i--) {
        for (int j = i + 1; j < N; j++) {
            a[i][N] -= a[i][j] * a[j][N];
            a[i][j] = 0;
        }
        a[i][N] = a[i][N] / a[i][i];
        print_matrix(a);
    }
}

// ガウス消去法を使って連立方程式を解く
void gauss_elimination(Matrix a)
{
    forward_elimination(a);
    backward_substitution(a);
}

//計算結果を表示する
void print_result(Matrix a)
{
    printf("====results====\n");
    for (int i = 0; i<N; i++) {
        printf(" x%d = %9.3lf\n", i + 1, a[i][N]);
    }
}

int main(int argc, char* argv[])
{
    FILE* ifp1 = NULL;  //入力用ファイルポインタ
    char* ifile1 = NULL;   //入力ファイル名
    ifile1 = argv[1];  //パラメータの1番目を入力ファイル名

    /*コマンドライン関数で読み込んだファイルを開く*/
    if (argc != 2) {   //実行時引数が1個なかったらエラーとする
        fprintf(stderr, "usage: %s inputfile outputfile\n", argv[0]);
        exit(1);
    }
    if ((ifp1 = fopen(ifile1, "rt")) == NULL) { //入力ファイルを開く
        fprintf(stderr, "Can't open file %s\a\n", ifile1); //開けなかったら終了
        exit(2);
    }

    /*解の書き込まれているファイルを開く。*/
    FILE* ifp2 = NULL;
    char ifile2[] = "b_vec.csv";
    if ((ifp2 = fopen(ifile2, "rt")) == NULL) { //入力ファイルを開く
        fprintf(stderr, "Can't open file %s\a\n", ifile2); //開けなかったら終了
        exit(3);
    }

    Matrix A = { 0 };

    scan_data1(ifp1, A);
    print_matrix(A);        //ファイルA確認
    scan_data2(ifp2, A);

    print_matrix(A);        //ファイルAB確認
    gauss_elimination(A);
    print_result(A);

    fclose(ifp1);   //ファイルを閉じる
    fclose(ifp2);

    return (0);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/09 14:40

    ありがとうございます!

    キャンセル

同じタグがついた質問を見る

  • C

    4131questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。