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

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

ただいまの
回答率

90.75%

  • C

    3448questions

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

行と列が違う配列の掛け算

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 495

nonbirikame

score 32

前提

書籍で勉強している学生です。
書籍の2周目をしています。
書籍の解答がないため問題のヒントや解説をしていただけると嬉しいです。

問題

4行3列の行列と3行4列の行列の積を求めるプログラムを作成せよ。
各構成要素の値はキーボードから読み込むこと。

該当のソースコード

    /*各配列の要素を掛け合わせる*/

    int l = 0;
    for(i = 0; i < 2; i++){
        for(j = 0; j < 3; j++){
            sum[l] = x[i][j];
            l++;
        }
    }

    int k = 0;
    for(i = 0; i < 3; i++){
        for(j = 0; j < 2; j++){
            sum[k] = sum[k] * y[i][j];
            k++;
        }
    }

疑問点

各構成要素の値を掛け合わせる時に、現在大きな二つのfor文を使用しているのですが。
これを一つにすっきりとまとめる方法があれば教えていただきたいです。

補足情報

書籍 : 新明解C言語 入門編
演習 5-10

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

行列の積を計算するためには、各要素の値を内積として計算する必要があります。
ですので、率直に組むと三重ループとなります。

C = A*B とすると、次のような感じです。

for(int row = 0; row < A_row; row++) {
    for(int col = 0; col < B_col; col++) {
        for(int i = 0; i < A_col; i++) {
            C[row][col] += A[row][i] * B[i][col];
        }
    }
}

ただし、Cの要素は0に初期化されているとします。
デバッグしていないのでちょっとしたミスがあったらごめんなさい。

おまけ

楽しそうなので自分なりに書いてみました。
あまり参考にならないかもしれませんが、せっかく作ったので載せておきます。

main.c

#include "matrix.h"
#include <stdlib.h>

#define SIZE(array) sizeof(array) / sizeof(array[0])

int main(int argc, char **argv) {
    MATRIX matrix_a, matrix_b, matrix_c;

    int raw_a[][3]= {
        { 3,  0,  5}, {-1,  5,  7}, { 1,  6, -3}, { 6,  3,  2}
    };
    make_matrix(&raw_a[0][0], SIZE(raw_a), SIZE(raw_a[0]), &matrix_a);

    int raw_b[][4]= {
        { 3,  1,  2,  3}, { 2,  4,  2,  6}, {-3,  3,  0,  1}
    };
    make_matrix(&raw_b[0][0], SIZE(raw_b), SIZE(raw_b[0]), &matrix_b);

    int raw_c[m_row(&matrix_a)][m_col(&matrix_b)];
    make_matrix(&raw_c[0][0], m_row(&matrix_a), m_col(&matrix_b), &matrix_c);
    compute_matrix_product(
        &matrix_a, &matrix_b, &matrix_c
    );

    print_matrix_w_info(&matrix_a);
    print_matrix_w_info(&matrix_b);
    print_matrix_w_info(&matrix_c);

    return EXIT_SUCCESS;
}

vector.h

#include <stdlib.h>

int compute_inner_product(
    const int *vector_a, const int *vector_b, size_t len
);

void print_vector(const int *vector, size_t len);

vector.c

#include "vector.h"
#include <stdio.h>
#include <stdlib.h>

void print_vector(const int *vector, size_t len) {
    for(size_t i = 0; i < len; i++) {
        printf("%4d ", vector[i]);
    }     
    printf("\n");
}

int compute_inner_product(
    const int *vector_a, const int *vector_b, size_t len) 
{  
    int sum = 0;
    for(size_t i = 0; i < len; i++) {
        sum += vector_a[i] * vector_b[i];
    }
    return sum;
}

matrix.h

#include <stdlib.h>

#define BUFFER_LEN 100
#define print_matrix_w_info(matrix) \
    print_matrix_w_info_(#matrix, matrix)

typedef struct {
    int *value_;
    size_t row_; size_t col_;
} MATRIX;

MATRIX *make_matrix(
    int *value, size_t row, size_t col, MATRIX *dst
);
MATRIX *input_matrix(MATRIX *dst);

const int *  m_value(const MATRIX *matrix);
const size_t m_row  (const MATRIX *matrix);
const size_t m_col  (const MATRIX *matrix);

int value_at    (const MATRIX *matrix, size_t row, size_t col);
int set_value_at(      MATRIX *matrix, size_t row, size_t col, int value);

int *make_horizontal_vector_from_matrix_row(
    const MATRIX *matrix, int *dst, int row_num
);
int *make_vertical_vector_from_matrix_col(
    const MATRIX *matrix, int *dst, int col_num
);

MATRIX *compute_matrix_product(
    const MATRIX *matrix_a, const MATRIX *matrix_b,
    MATRIX *dst
);

void print_matrix(const MATRIX *matrix);
void print_matrix_w_info_(const char *name, const MATRIX *matrix);

matrix.c

#include "vector.h"
#include "matrix.h"

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

MATRIX *make_matrix(
    int *value, size_t row, size_t col, MATRIX *dst)
{
    dst->value_ = value;
    dst->row_   = row;
    dst->col_   = col;

    return dst;
}
MATRIX *input_matrix(MATRIX *dst) {
    char buffer[BUFFER_LEN];

    printf("%d x %d\n", m_row(dst), m_col(dst));
    for(size_t row = 0; row < m_row(dst); row++) {
        fgets(buffer, BUFFER_LEN, stdin);

        int num = atoi(strtok(buffer, " "));
        for(size_t col = 0; col < m_col(dst); col++) {
            set_value_at(dst, row, col, num);
            num = atoi(strtok(NULL, " "));
        }
    }
    return dst;
}

const int *  m_value(const MATRIX *matrix) { return matrix->value_; }
const size_t m_row  (const MATRIX *matrix) { return matrix->row_;   }
const size_t m_col  (const MATRIX *matrix) { return matrix->col_;   }

int value_at(const MATRIX *matrix, size_t row, size_t col) {
    return m_value(matrix)[row*m_col(matrix) + col];
}
int set_value_at(MATRIX *matrix, size_t row, size_t col, int value) {
    matrix->value_[row*m_col(matrix) + col] = value;
}

int *make_horizontal_vector_from_matrix_row(
    const MATRIX *matrix, int *dst, int row_num)
{
    for(size_t col = 0; col < m_col(matrix); col++) {
        dst[col] = value_at(matrix, row_num, col);
    }
    return dst;
}
int *make_vertical_vector_from_matrix_col(
    const MATRIX *matrix, int *dst, int col_num)
{
    for(size_t row = 0; row < m_row(matrix); row++) {
        dst[row] = value_at(matrix, row, col_num);
    }
    return dst;
}

MATRIX *compute_matrix_product(
    const MATRIX *matrix_a, const MATRIX *matrix_b,
    MATRIX *dst
) {
    int *work_row_vec = (int *)malloc(sizeof(int) * m_col(matrix_a));
    int *work_col_vec = (int *)malloc(sizeof(int) * m_row(matrix_b));

    for(size_t row = 0; row < m_row(matrix_a); row++) {
        for(size_t col = 0; col < m_col(matrix_b); col++) {
            make_horizontal_vector_from_matrix_row(
                matrix_a, work_row_vec, row
            );
            make_vertical_vector_from_matrix_col(
                matrix_b, work_col_vec, col
            );

            set_value_at(
                dst, row, col, compute_inner_product(
                    work_row_vec, work_col_vec, m_row(matrix_b)
                )
            );
        }
    }

    free(work_row_vec);
    free(work_col_vec);
    return dst;
}

void print_matrix(const MATRIX *matrix) {
    int work[m_col(matrix)];
    for(size_t row = 0; row < matrix->row_; row++) {
        print_vector(
            make_horizontal_vector_from_matrix_row(
                matrix, work, row
            ), m_col(matrix)
        );
    }
}
void print_matrix_w_info_(const char *name, const MATRIX *matrix) {
    if(name[0] == '&') name++;
    printf("%s\n", name);

    if(matrix->value_ == NULL) {
        printf("Matrix is not initialized\n");
    }
    else {
        print_matrix(matrix);
    }

    printf("row->%d / col->%d\n", m_row(matrix), m_col(matrix));
    printf("\n");
}

実行結果

matrix_a
   3    0    5
  -1    5    7
   1    6   -3
   6    3    2
row->4 / col->3

matrix_b
   3    1    2    3
   2    4    2    6
  -3    3    0    1
row->3 / col->4

matrix_c
  -6   18    6   14
 -14   40    8   34
  24   16   14   36
  18   24   18   38
row->4 / col->4

たまにCに触れると楽しいです。
ランタイムエラーへの対策ががばがばなのはご愛嬌です。
実際にはmallocの返り値や標準入力をチェックした方が丁寧でしょう。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/14 19:31

    このmatrix.hはご自分で作られたのですか?
    ヘッダを自作できるとは、知らなかったので…

    キャンセル

  • 2017/10/14 19:48

    平たく言えば、ヘッダは『プロトタイプ宣言をまとめたもの』です(だいぶ語弊はある)。
    ヘッダをインクルードすることで、関数を任意のタイミングで使えるようにしているのです。

    キャンセル

  • 2017/10/14 19:51

    私の書いたコードは、ポインタを取りまわしていたり、構造体をオブジェクト指向的に用いていたりするので、初心者にはちょっと高度な内容だと思います。
    『なんか、こんな感じでも書けるんだなぁ』と思うくらいで大丈夫です。

    キャンセル

  • 2017/10/14 20:10

    よっ良かった…
    自分にとって高度だったので、後々理解できるように頑張ります。

    キャンセル

  • 2017/10/14 20:14

    頑張ってくださいね。
    この手の演算は面倒なので、実用する際には普通既存のライブラリを使います。
    逆に言うと学習目的以外では自作することはあまりないので、ちょっと楽しんでしまいました。

    キャンセル

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

  • ただいまの回答率 90.75%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    100になる直前の加算結果出力

    javaで開始値と終了値を入力してその間の偶数を加算していき、合計が100を超えたら「数値が100を超えたため、処理を中止します。」とメッセージを出し、かつ合計が100になる前の加

  • 受付中

    解決策が分かりません・・・

    5人の点数をキーボードから読み込んで、合計点、平均点、最高点、最低点を表示したいのですが(点数は0以上100以下)、 実行例 5人の点数を入力してください。 1番:95 2

  • 解決済

    C言語2次元配列で関数を使用せずにビンゴゲーム作成したい

    C言語2次元配列で関数を使用せずにビンゴゲーム作成したいです。 3行*3列の簡単なものですが、素人でもわかるように ご教示お願いします。 入力は1,3,6,8,7,9,2

  • 解決済

    C言語について式だけで繰り返しを表現可能?

    C89仕様では文を使わず式だけで繰り返しを表現することは可能なのでしょうか。 よろしくお願いいたします。

  • 解決済

    HTMLで配列の値を合計する方法

    HTMLでinputタグでデータを取得して、次のページに移動したときに 前処理としてデータを確認したいと思っています。 しかしその値をうまく比べることができません。 PHP5.5で

  • 解決済

    二桁の数字を一桁にする

    例えば int = 10; ならば1 int = 18; ならば9のように 二桁の数字を一桁の数字にするには プログラミングでどのように表現するべき なのでしょ

  • 解決済

    itertoolsからintで要素をもらう方法

    itertoolsのデカルト積(?…という名前も初めて知りました;;)で配列にもらったものを合計したいのですが、配列内にstrで入ってくるため、エラーとなってしまいます。 fo

  • 解決済

    良い方法を教えてください。

    前提・実現したいこと x配列の各数字ごとに足し算結果を出したい。 「1」なら sum1 = 50 + 40; 「2」なら sum2 = 30 + 20; : : 「5」なら sum

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

  • C

    3448questions

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