行列計算について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
peace

行列計算について

#1

投稿記事 by peace » 17年前

はじめまして!大学生やってるpeaceです。
大学の必修科目の課題ができなくて悩んでいます(;_;)
まず乱数を生成しファイルに出力するプログラムを作成します。
ここで二つのテキストファイルに乱数を出力させました。
次にそのプログラムを実行後テキストファイルに出力された乱数を2つの2次元配列に読み込み行列の和と積を求め演算結果をファイルに出力するプログラムを作るというものです。
乱数をファイルに出力するプログラムは問題無いのですが、乱数を2次元配列に読み込んで行列演算し、結果をファイルに出力するプログラムがうまくできません。取りあえず1個目のプログラムは問題ないと思うので2個目のプログラムを書きます。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
       FILE *myfile1;
       FILE *myfile2;
       FILE *myfile3;
       int **array1 = (int **)malloc(sizeof(int)*100);
       int **array2 = (int **)malloc(sizeof(int)*100);
       int i,j,k,num1,num2;
       int wa[20][20],seki[20][20];
       char line[124];
       
       for(i=0; i<100; ++i)
       {
              array1 = (int*)malloc(sizeof(int)*100);
       }
       if((myfile1=fopen("1つ目のテキストファイル名","r"))==NULL){
       fprintf(stderr,"Cannot open 1つ目のテキストファイル名\n");
       return 1;
       }
       for(i=0; i<10; ++i)
       {
             for(j=0; j<10; ++j)
             {
             fgets(line,sizeof(line),myfile1);
             sscanf(line,"%d",&num1);
             array1[j] = num1;
             }
       }
       for(i=0; i<10; ++i)
       {
             array2 = (int*)malloc(sizeof(int)*100);
       }
        if((myfile2=fopen("二つ目のテキストファイル名","r")) == NULL){
           fprintf(stderr,"Cannnot open 二つ目の乱数ファイル名\n");
            return 1;
       }
       for(i=0; i<10; ++i)
       {
           for(j=0; j<10; ++j)
           {
           fgets(line,sizeof(line),myfile2);
           sscanf(line,"%d",&num2);
           array2[j] = num2;
           }
        }
        if((myfile3=fopen("演算結果を書き込むテキストファイル名\n")
        return 1;
        }
        fprintf(myfile3,"行列の和\n");
        for(i=0; i<10; i++){
        for(j=0; j<10; j++){
        wa[j] = array[j] + array2[j];
        fprintf(myfile3, "%d ",wa[j] );
        }
        fprintf(myfile3, "\n");
        fprintf(myfile3,"行列の積\n");
        for(i=0; i<10; i++) {
                 for(j=0; j<10; j++){
                 seki[j] = 0;
                 for(k=0; k<10; k++)
                 seki[j] += array1[i][k] *array2[k][j];
                 fprintf(myfile3,"%d",seki[i][j] );}
        fprintf(myfile3,"\n" );
        }
        fclose(myfile3);
        fclose(myfile1);
        for(i=0; i<100; ++i)
        {
                free( array1[i] );
        }
        free( array1 );
        fclose(myfile2);
        for(i=0; i<100; ++i)
        {
                free( array2[i] );
        }
        free( array2 );
        return 0;
}

直したいところは固定長の行列の生成と演算しかできないところです。malloc使用も固定長なので駄目だといわれてしまいました。
教えてもらえるような友人もいなく独りでずっと考えてたのですが
手のつけようがなかったので、手助けお願いしますm(_ _)m
年末は何かと忙しい時期なのに、申し訳ないです(T_T)

Justy

Re:大学の課題についてです

#2

投稿記事 by Justy » 17年前

 固定サイズの行列がだめなら行列の縦横のサイズはどうやって決定するんでしょう?

 又、読み込むテキストファイルはどのように書かれているのでしょうか?

peace

Re:大学の課題についてです

#3

投稿記事 by peace » 17年前

まずは御返事ありがとうございます^_^
>固定サイズの行列がだめなら行列の縦横のサイズはどうやって決定するんでしょう?

そこで手がつけようもなくなり悩んでいます。
動的な行列っていうことは、読み込むデータ数によって縦横のサイズが変わるってことですよね?そうなるとデータの数によって行列が作れない場合など、でてきて一体どうすればって感じです(;_;)先生に一回プログラムを提出したところ、こう直すように言われたのですが先生の言い方が悪かったのか私が理解していないのか・・・。

先生にプログラムの駄目だしされた時点では
int wa[5][5],seki[5][5];/*line11*/
for(文A;条件B;文C)の全ての条件Bを
変数<5としていました。

テキストファイルについては2つとも0~100の範囲の乱数を
i_random=rand()%101
fprintf(myfile1,"%d\n",i_random);
で30個書き込んでます。
45
86
47
1
48
という感じに30行続いてます。
手元にプログラムソースがプリントしかないので読みづらい所が
あるかもしれないですがよろしくお願いします。

Justy

Re:大学の課題についてです

#4

投稿記事 by Justy » 17年前

 では、こうしてみてはどうでしょう。

 課題1の方のテキストに乱数を出力する際に
 
・ 乱数5~30くらいの数値を2つ出して、それを行列サイズX、Yとする。
・ 仮にそのXが8、Yが6だったら

[color=#d0d0ff" face="monospace]8, 6
726 248 952 828 633 484 436 385
376 927 983 218 712 838 820 645
896 240 500 114 671 48 442 877
342 754 562 807 841 917 117 959
132 662 883 122 654 33 17 977
559 216 475 88 422 657 576 352
[/color]

 のようにテキストを出力してみてはどうでしょうか。


 課題2の方ではテキストの先頭に行列サイズが入っているので、そのサイズ情報を信用して次の行からの行列を読む、という方法です。

peace

Re:大学の課題についてです

#5

投稿記事 by peace » 17年前

8,6だけ行列のサイズとして読み込ませるということは
strtok関数を使えばいいのでしょうか・・・
ほとんど知識がないので見当はずれなこと言ってたらすいません。
元々乱数の出力させるファイルを一つにして、strtok関数を使って
2つの行列を作ろうとしてたのですが、使い方がよく分からず、
断念した関数です(T_T)

管理人

Re:大学の課題についてです

#6

投稿記事 by 管理人 » 17年前

fgetcでもstrtokでもいいんじゃないでしょうか?

両者とも読み取った文字をatoiしてやればいいんじゃないでしょうか?

box

Re:大学の課題についてです

#7

投稿記事 by box » 17年前

> 8,6だけ行列のサイズとして読み込ませるということは
> strtok関数を使えばいいのでしょうか・・・

こんなサンプルを動かしてみてください。
#include <stdio.h>

int main(void)
{
	char s[/url] = "8, 6";			/* 実際にはファイルから読んだつもり */
	int m, n;
	
	sscanf(s, "%d,%d", &m, &n);
	printf("%d %d\n", m, n);
	return 0;
}

管理人

Re:大学の課題についてです

#8

投稿記事 by 管理人 » 17年前

strtokの使い方はこんな感じでどうでしょうか?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
	char str[/url] = "8,6,7,9,2",st[5][5];
	char *tp;
	int i=0,s[5];
	tp = strtok( str, "," );
	strcpy(st,tp);
	i++;
	while ( tp != NULL ) {
		tp = strtok( NULL,"," );
		if ( tp != NULL ){ 
			strcpy(st,tp);
			i++;
		}
	}
	for(i=0;i<5;i++){
		s=atoi(st);
		printf("%d\n",s);
	}
	return 0;
}


もっとスマートにかけると思いますが、わかりやすくダラダラと書きました。

peace

Re:大学の課題についてです

#9

投稿記事 by peace » 17年前

御返事ありがとうございます。
自宅でプログラミングやる環境がないので
明日学校で試してみようと思います。
明日パソコン演習室が使える時間が3時間で、締め切りが火曜日(T_T)
やはり、プログラミングを学ぶには自宅で環境作らないと
よろしくないみたいですね。

管理人

Re:大学の課題についてです

#10

投稿記事 by 管理人 » 17年前

スマートに書くとこんな感じでしょうか。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
	char str[/url] = "8,6,7,9,2";//格納されている文字列
	char *tp;//トークンへのポインタ
	int i=0,s[5];//forで使うiと数値を格納するs
	tp = strtok( str ,"," );//読み取る文字列はstr。区切るのは「,」
	while (1){
		if ( tp != NULL ){ //最後まで読み取ってなかったら
			s=atoi(tp);//区切られた区間の文字列をint型に変換して格納
			i++;
		}
		else//最後まで読み取られたらブレイク
			break;
		tp = strtok( NULL, "," );//「,」を区切りにして次までのトークンへのポインタを返す
	}
	for(i=0;i<5;i++)
		printf("%d\n",s);
	return 0;
}

管理人

Re:大学の課題についてです

#11

投稿記事 by 管理人 » 17年前

cのコンパイラはフリーであるので、
borlandというフリーのコンパイラを導入されてみてはいかがでしょうか?

peace

Re:大学の課題についてです

#12

投稿記事 by peace » 17年前

コンパイラはDLできたみたいですが
CPad for Borland C++Compilerっていうテキストエディタが
お金かかるみたいで・・・。
今すぐに導入するのは難しそうです。

box

Re:大学の課題についてです

#13

投稿記事 by box » 17年前

> CPad for Borland C++Compiler

これは、「送金義務がないシェアウェア」という、
ユニークな形態のソフトウェアです。
送金しなくても、機能に制限がかかることなく自由に使えます。

無料の開発環境では、BCC Developerというのがあります。
http://www.hi-ho.ne.jp/jun_miura/

peace

Re:大学の課題についてです

#14

投稿記事 by peace » 17年前

ありがとうございます。
ちょっと今から用事あるので22時過ぎからチャレンジしてみようと思います^^

Justy

Re:大学の課題についてです

#15

投稿記事 by Justy » 17年前

 よくかんがえたら。
 行列のサイズ情報をテキストに書き出してるんだから、わざわざ数値を横に並べなくても良かったですよね。
[color=#d0d0ff" face="monospace]8, 6 
726 248 952 828 633 484 436 385
.....[/color]
 じゃなくて
[color=#d0d0ff" face="monospace]8
6 
726
248
952
828
633
484
436
385
.....[/color]
 こうとか。
 この方が楽かも。

管理人

Re:大学の課題についてです

#16

投稿記事 by 管理人 » 17年前

別にテキストエディタなんて何でもいいんじゃないですか?
極端な話、メモ帳でも出来ますし。

コンパイラの導入はこちらから
http://www.borland.com/jp/products/cbui ... piler.html

コンパイラの設定はこちら
http://homepage3.nifty.com/norinoyama/c ... p_bcc.html

エディタは秀丸とかどうでしょう?
http://www.vector.co.jp/soft/dl/win95/w ... 86280.html

peace

Re:大学の課題についてです

#17

投稿記事 by peace » 17年前

とても親切に答えていただいて凄く助かります^^
一応コンパイラの環境設定まで終わったのですが
色々と手間取って思ったよりも時間がかかりそうなので、
家で環境を作るのは明日にしようと思います。
明日は朝5時に起きないといけないので今日は寝ます。
留年の2文字が背後から近づいてきてる(T_T)

管理人

Re:大学の課題についてです

#18

投稿記事 by 管理人 » 17年前

コンパイラの設定って慣れてないと時間かかりますよね!

特に「環境変数?」なんじゃそりゃ!
みたいなツボにはまると朝までかかったりw
とりあえずコマンドプロンプト出して
bcc
と入力したら説明が色々出てくるようになれば、OKです。

留年の危機とは、私と同じような道通ってますねぇ。
嫌いな科目はほんとほっとくタイプなんで^^;
スレスレで進級してきましたよw

また何かわからなかったら聞いてください☆

peace

Re:大学の課題についてです

#19

投稿記事 by peace » 17年前

色々と設定が多く(ファイルの拡張子?とか・・)時間がかかり、課題の方に支障がでそうなので
時間に余裕ができてから、プログラミングできる環境を作ってみようと思います(^_^;)
取りあえずはJustyさんと管理人さんとboxさんのプログラムを参考に
今日はやってみようと思います。
まだ明日も3時間程演習室が使えるのでがんばってっ見ようと思います!

管理人

Re:大学の課題についてです

#20

投稿記事 by 管理人 » 17年前

インストールにかかる時間ですが、そこまでかからないですよ。
やり方がわかっている人がすれば10分位だと思うので、
どこで躓くかが問題ですが・・。
どこか躓いたらいつでも聞いてください。
その方が早いと思うので。

peace

Re:大学の課題についてです

#21

投稿記事 by peace » 17年前

学校行ったんですがこの掲示板がアクセス禁止になってて見れませんでした(T_T)
皆さんのせっかくの助言を思い出しながらやったのですが、
自分の力不足のせいで活かすことができませんでした、ごめんなさいm(_ _)m
結局行列のサイズの指定は行列を全て正方行列にし、
コマンドラインから行おうとしてみたのですが、
セグメンテーションエラーが出てうまくいきませんでした。
取りあえずやったところまで載せてみますが、全然自信がないです・・・。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
       FILE *myfile1;
       FILE *myfile2;
       FILE *myfile3;
       int **array1 = (int **)malloc(sizeof(int)*100);
       int **array2 = (int **)malloc(sizeof(int)*100);
       int i,j,k,num1,num2,a;
       int wa[20][20],seki[20][20];
       char line[124],buff[124];
       
       for(i=0; i<100; ++i)
       {
              array1 = (int*)malloc(sizeof(int)*100);
       }
       printf("何次正方行列にするか指定してください>>");
       fgets(buff,sizeof(buff),stdin);
       sscanf(buff,"%d",&a);
           
       if((myfile1=fopen("1つ目のテキストファイル名","r"))==NULL){
       fprintf(stderr,"Cannot open 1つ目のテキストファイル名\n");
       return 1;
       }
       for(i=0; i<a; ++i)
       {
             for(j=0; j<a; ++j)
             {
             fgets(line,sizeof(line),myfile1);
             sscanf(line,"%d",&num1);
             array1[j] = num1;
             }
       }
       for(i=0; i<100; ++i)
       {
             array2 = (int*)malloc(sizeof(int)*100);
       }
        if((myfile2=fopen("二つ目のテキストファイル名","r")) == NULL){
           fprintf(stderr,"Cannnot open 二つ目の乱数ファイル名\n");
            return 1;
       }
       for(i=0; i<a; ++i)
       {
           for(j=0; j<a; ++j)
           {
           fgets(line,sizeof(line),myfile2);
           sscanf(line,"%d",&num2);
           array2[j] = num2;
           }
        }
        if((myfile3=fopen("演算結果を書き込むテキストファイル名\n")
        return 1;
        }
        fprintf(myfile3,"行列の和\n");
        for(i=0; i<a; i++){
        for(j=0; j<a; j++){
        wa[j] = array[j] + array2[j];
        fprintf(myfile3, "%d ",wa[j] );
        }
        fprintf(myfile3, "\n");
        fprintf(myfile3,"行列の積\n");
        for(i=0; i<a; i++) {
                 for(j=0; j<a; j++){
                 seki[j] = 0;
                 for(k=0; k<a; k++)
                 seki[j] += array1[i][k] *array2[k][j];
                 fprintf(myfile3,"%d",seki[i][j] );}
        fprintf(myfile3,"\n" );
        }
        fclose(myfile3);
        fclose(myfile1);
        for(i=0; i<100; ++i)
        {
                free( array1[i] );
        }
        free( array1 );
        fclose(myfile2);
        for(i=0; i<100; ++i)
        {
                free( array2[i] );
        }
        free( array2 );
        return 0;
}


拙いプログラムでごめんなさいm(_ _)m
どうか間違いの指摘をお願い致します。
全然違う!って場合は申し訳ないですが完成したプログラムを頂きたいです。

box

Re:大学の課題についてです

#22

投稿記事 by box » 17年前

【乱数を2つのテキストファイルに書き込むプログラム】
この例では、正方行列の行(=列)の数を2~10とし、1~20の範囲の乱数を
2つのファイルに書き込んでいます。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	FILE *fp1, *fp2;
	int row, i;
	
	fp1 = fopen("rand1.dat", "w");
	if (fp1 == NULL)
		fprintf(stderr, "file open error\n"), exit(1);
	fp2 = fopen("rand2.dat", "w");
	if (fp2 == NULL)
		fprintf(stderr, "file open error\n"), exit(1);
	
	do {
		printf("正方行列の行(列)の数(2~10):");
		scanf("%d", &row);
	} while (row < 2 || 10 < row);
	
	fprintf(fp1, "%d\n", row);
	fprintf(fp2, "%d\n", row);
	
	srand((unsigned int) time(NULL));
	for (i = 0; i < row * row; i++) {
		fprintf(fp1, "%d\n", rand() % 20 + 1);
		fprintf(fp2, "%d\n", rand() % 20 + 1);
	}
	fclose(fp1), fclose(fp2);
	return 0;
}

【2つのファイルから乱数を読み込んで2つの正方行列にセットし、和と積を求めるプログラム】
上のプログラムで作成したテキストファイルから正方行列の要素を読み取り、
和と積を求めます。計算結果を、テキストファイルに書き込みます。
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	FILE *fp1, *fp2, *fp3;
	int row, i, j, k;
	int **arr1, **arr2;
	
	fp1 = fopen("rand1.dat", "r");
	if (fp1 == NULL)
		fprintf(stderr, "file open error\n"), exit(1);
	fp2 = fopen("rand2.dat", "r");
	if (fp2 == NULL)
		fprintf(stderr, "file open error\n"), exit(1);
	fp3 = fopen("result.dat", "w");
	if (fp3 == NULL)
		fprintf(stderr, "file open error\n"), exit(1);
	
	fscanf(fp1, "%d", &row);
	fscanf(fp2, "%d", &row);
	
	arr1 = (int **) malloc(sizeof(int *) * row);
	if (arr1 == NULL)
		fprintf(stderr, "out of memory\n"), exit(1);
	for (i = 0; i < row; i++) {
		arr1 = (int *) malloc(sizeof(int) * row);
		if (arr1 == NULL)
			fprintf(stderr, "out of memory\n"), exit(1);
	}
	
	arr2 = (int **) malloc(sizeof(int *) * row);
	if (arr2 == NULL)
		fprintf(stderr, "out of memory\n"), exit(1);
	for (i = 0; i < row; i++) {
		arr2 = (int *) malloc(sizeof(int) * row);
		if (arr2 == NULL)
			fprintf(stderr, "out of memory\n"), exit(1);
	}
	
	fprintf(fp3, "【行列1】\n");
	for (i = 0; i < row; i++) {
		for (j = 0; j < row; j++) {
			fscanf(fp1, "%d", &arr1[j]);
			fprintf(fp3, "%5d", arr1[j]);
		}
		fprintf(fp3, "\n");
	}
	fprintf(fp3, "\n\n");
	
	fprintf(fp3, "【行列2】\n");
	for (i = 0; i < row; i++) {
		for (j = 0; j < row; j++) {
			fscanf(fp2, "%d", &arr2[j]);
			fprintf(fp3, "%5d", arr2[j]);
		}
		fprintf(fp3, "\n");
	}
	fprintf(fp3, "\n\n");
	
	fprintf(fp3, "【和】\n");
	for (i = 0; i < row; i++) {
		for (j = 0; j < row; j++)
			fprintf(fp3, "%8d", arr1[j] + arr2[j]);
		fprintf(fp3, "\n");
	}
	fprintf(fp3, "\n\n");
	
	fprintf(fp3, "【積】\n");
	for (i = 0; i < row; i++) {
		for (j = 0; j < row; j++) {
			int sum;
			for (sum = k = 0; k < row; k++)
				sum += arr1[i][k] * arr2[k][j];
			fprintf(fp3, "%8d", sum);
		}
		fprintf(fp3, "\n");
	}
	fprintf(fp3, "\n\n");
	
	for (i = 0; i < row; i++)
		free(arr1[i]), free(arr2[i]);
	free(arr1), free(arr2);
	fclose(fp1), fclose(fp2), fclose(fp3);
	return 0;
}

peace

Re:大学の課題についてです

#23

投稿記事 by peace » 17年前

boxさん本当に有難うございます(T_T)
それにしても私のプログラムは全然違ってたみたいですね・・・
あとで皆さんのプログラムを見てじっくり勉強させていただきます。
今はレポートの完成が最優先ですが。
アドバイスを頂いた皆さんにはとても感謝してますm(_ _)m
今までプログラミングに苦手意識をもってて遠ざけてきましたが
今回真正面からぶつかってみて少しC言語に興味がもてました。
次回ここの掲示板に現れるときはアドバイスする側になってるようにしたいです。
本当にありがとうございました。

管理人

Re:大学の課題についてです

#24

投稿記事 by 管理人 » 17年前

wa[j] = array[j] + array2[j];

ここ
array1ですよね?

peace

Re:大学の課題についてです

#25

投稿記事 by peace » 17年前

あ、そうです。
プリントに印刷したのを見ながら打ってるので抜けちゃってました。
ごめんなさい。

管理人

Re:大学の課題についてです

#26

投稿記事 by 管理人 » 17年前

手打ちですか~(T_T)
お疲れ様でしたm(_ _)m

peace

Re:大学の課題についてです

#27

投稿記事 by peace » 17年前

無事終わったので解決にしときます。
それにしてもC言語について余り知識がない私でも
boxさんのプログラムは凄い綺麗だなぁと感じました。
本当に皆さんありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る