またもや宿題でつまずいております・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
れお
記事: 113
登録日時: 13年前

またもや宿題でつまずいております・・・

#1

投稿記事 by れお » 13年前

n×n正方行列Aに対して、A^2を求めるプログラムなんですが・・・
コード内ではY=X^2としてYを出力しようとしています。

コード:

 

 //n×n正方行列Aに対して、Aのk乗を求めるプログラム
 #include <stdio.h>
 #define N 5

 void Input_matrix(float (*X)[N],int n)   //2次元配列のポインタ。後ろのほうしか必要じゃない
 {
	 int i=0,j=0;
	 for(;i<n;i++)
	 {
		 for(;j<n;j++)
		 {
			 printf("行列Aの%d行%d列成分の値を入力してください\n",i+1,j+1);
			 scanf("%f",&X[i][j]);
		 }
	 }

	 return ;
 }


 void Multiply_matrix(float (*X)[N],float (*Y)[N],int n)
 {
	 int i=0,j=0,k=0;
	 for(;i<n;i++)
	 {
		 for(;j<n;j++)
		 {
			 for(;k<n;k++)
			 {
				 Y[i][j]+=X[i][k]*X[k][j];
			 }
		 }
	 }
	 return ;
 }

 int main(void)
 {
	 int i=0,j=0;
	 float X[N][N],Y[N][N];
	 int n=0;
	 printf("n(<=5)を決めてください。\nn=");
     scanf("%d\n",&n);

     if(n>5)
     {
    	 printf("エラー:n<=5となるnを入力してください\n");
    	 return (-1);
     }
     Input_matrix(X,n);//行列の入力
     Multiply_matrix(X,Y,n);//行列の計算

     for(;i<n;i++)
     {
    	 for(;j<n;j++)
    	 {
    		 printf("行列Aの%d行%d列成分は…%f\n",i+1,j+1,Y[i][j]);
    	 }
     }
	 return 0;
 }

 

windowsで実行してみるとうまくいきません。。。
おそらくLinaxでもうまくいきません。
どこがおかしいのでしょう?
エラーはないのですが、実行結果が明らかにおかしいです・・・><
まだC初心者から脱していないのでできるだけ訂正箇所、理由など詳しくお願いしたいです・・・><

box
記事: 2002
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#2

投稿記事 by box » 13年前

コードを全部見たわけではないですが、ぱっと見で気づいた点を…。
れお さんが書きました:

コード:

	 int i=0,j=0;
	 for(;i<n;i++)
	 {
		 for(;j<n;j++)
		 {
			 printf("行列Aの%d行%d列成分の値を入力してください\n",i+1,j+1);
			 scanf("%f",&X[i][j]);
		 }
	 }
内側のfor文のループ制御用に使っている変数jの初期化を行なうタイミングは、
『ループの外側1回だけ』で本当にOKですか?
れお さんが書きました:

コード:

	 int i=0,j=0;
	 for(;i<n;i++)
		 for(;j<n;j++)
そもそも、n回ループしたいときの書き方で、こういうのはめずらしいと思います。ちょっと見かけたことがないですね。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#3

投稿記事 by れお » 13年前

!?
ありがとうございます!!
内側にいれる必要がありますね^^

ちょっと今忙しいので確認できないかもですが。それは確実です。
ありがとうございます^^
他にもあればお願いします・・・><

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#4

投稿記事 by れお » 13年前

確認しました^^
多分いけました^^
ここから任意の整数kにおけるAのk乗を求めるプログラムにかえたいので自力でちょっとがんばってみます。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#5

投稿記事 by れお » 13年前

コード:

 //n×n正方行列Aに対して、Aのk乗を求めるプログラム
 #include <stdio.h>
 #define N 5

 void Input_matrix(float (*X)[N],int n)   //2次元配列のポインタ。後ろのほうしか必要じゃない
 {
     int i=0,j=0;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("行列Aの%d行%d列成分の値を入力してください\n",i+1,j+1);
             scanf("%f",&X[i][j]);
         }
     }

     return ;
 }


 void Multiply_matrix(float (*X)[N],float (*Y)[N],int n)
 {
     int i=0,j=0,k=0;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             for(k=0;k<n;k++)
             {
                 Y[i][j]+=X[i][k]*X[k][j];
             }
         }
     }
     return ;
 }

 int main(void)
 {
     int i=0,j=0;
     float X[N][N],Y[N][N];
     int n=0;
     printf("n(<=5)を決めてください。\nn=");
     scanf("%d",&n);

     if(n>5)
     {
         printf("エラー:n<=5となるnを入力してください\n");
         return (-1);
     }
     Input_matrix(X,n);//行列の入力
     Multiply_matrix(X,Y,n);//行列の計算

     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("行列Aの%d行%d列成分は…%f\n",i+1,j+1,Y[i][j]);
         }
     }
     return 0;
 }
なんかおかしいです・・・まだ2乗の段階なんですが、おかしいです。
実行結果が以下のようになります。。。
n(<=5)を決めてください。
n=2
行列Aの1行1列成分の値を入力してください
1
行列Aの1行2列成分の値を入力してください
1
行列Aの2行1列成分の値を入力してください
1
行列Aの2行2列成分の値を入力してください
1
行列Aの1行1列成分は…0.311319
行列Aの1行2列成分は…1.999983
行列Aの2行1列成分は…2.000000
行列Aの2行2列成分は…2.000000

あきらかにおかしいです・・・
どこがおかしいのでしょうか??;
デバッグができないため確認もできません><

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: またもや宿題でつまずいております・・・

#6

投稿記事 by みけCAT » 13年前

Ideoneで試したところ、このような感じになりました。
http://ideone.com/RGHTI

コード:

n(<=5)を決めてください。
n=2
行列Aの1行1列成分の値を入力してください
1
行列Aの1行2列成分の値を入力してください
1
行列Aの2行1列成分の値を入力してください
1
行列Aの2行2列成分の値を入力してください
1
行列Aの1行1列成分は…1.999983
行列Aの1行2列成分は…1.999983
行列Aの2行1列成分は…2.000000
行列Aの2行2列成分は…1.999983
誤差範囲だと思います。
あなたが使っている環境(OS、コンパイラの種類とバージョン、など)を教えてください。
とりあえず、行列Yを初期化していないのは大丈夫ですか?

floatをdoubleにすると、表示される範囲では正確に求まったようです。
http://ideone.com/4VtYR
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: またもや宿題でつまずいております・・・

#7

投稿記事 by かずま » 13年前

初期化されてない Y に、値をどんどん足しこんでいますよ。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#8

投稿記事 by れお » 13年前

宿題がfloat指定だったのでfloatのままやりましたが、やはり指摘どおり初期化してないからでした。ありがとうございました。
doubleとfloat・・・変えるだけでうまくいくなんてことあるんですね^^;違いを全然理解してないもので;

とりあえずおかげさまで解決いたしましたので、提出したらk乗に挑戦します。
ありがとうございました。^^

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#9

投稿記事 by れお » 13年前

k乗にいくまえに・・・^^;
float *p[ ]  と  float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
なんで*p[ ] だとうまくいかないんでしょう・・・・

pは自分のコードでいうXやYなどにあたります

box
記事: 2002
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#10

投稿記事 by box » 13年前

れお さんが書きました: float *p[ ]  と  float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
前者は、「pはポインターの配列である」ことを意味します。
後者は、「pは配列へのポインターである」ことを意味します。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: またもや宿題でつまずいております・・・

#11

投稿記事 by ISLe » 13年前

れお さんが書きました:float *p[ ]  と  float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
float *p[]
float*型を要素に持つ配列。
p[0]~p[n]それぞれがfloatを指すポインタです。

float (*p)[]
float型を要素に持つ配列を指すポインタ。
p自体は配列ではなくひとつの要素を指します。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#12

投稿記事 by れお » 13年前

OKです^^
助かります!!

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#13

投稿記事 by れお » 13年前

コード:

//n×n正方行列Aに対して、Aのk乗を求めるプログラム
 #include <stdio.h>
 #define N 5

 void Input_matrix(float (*X)[N],float (*Y)[N],int n)   //2次元配列のポインタ。後ろのほうしか必要じゃない
 {
     int i=0,j=0;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("行列Aの%d行%d列成分の値を入力してください\n",i+1,j+1);
             scanf("%f",&X[i][j]);
               Y[i][j]=0;//Yにプラスしていくから初期化してる。下の関数のZのこと
         }
     }

     return ;
 }


 void Multiply_matrix(float (*X)[N],float (*Y)[N],float (*Z)[N],float (*W)[N],int n,int k)
 {
     int h=0,i=0,j=0,p=0;
     if(k==1)
     {
         for(i=0;i<n;i++)
         {
             for(j=0;j<n;j++)
             {
                 Y[i][j]=X[i][j];
             }
         }
    	 return;
     }
     else
     {
    	 for(i=0;i<n;i++)
    	 {
    		 for(j=0;j<n;j++)
    		 {
    			 for(p=0;p<n;p++)
    			 {
    				 Z[i][j]+=X[i][p]*Y[p][j];//Zを初期化しないと計算があわない;
    			 }
    		 }
    	 }
    	 if(k==2)
    	 {
    		 return;
    	 }
    	 else//累乗
    		 {
				 for(h=0;h<k-2;h++)
				 {
					 for(i=0;i<n;i++)
					 {
						 for(j=0;j<n;j++)
						 {
							 for(p=0;p<n;p++)
							 {
								 W[i][j]+=Z[i][p]*Y[p][j];
							 }
						 }
					 }
					 for(i=0;i<n;i++)
					 {
						 for(j=0;j<n;j++)
						 {
							 Z[i][j]=W[i][j];
						 }
					 }
				 }
    		 }
    	 return;
     }
 }

 int main(void)
 {
     int i=0,j=0,k=0;
     float X[N][N],Y[N][N],Z[N][N];
     int n=0;
     printf("n(<=5)を決めてください。n=");
     scanf("%d",&n);

     if(n>5)
     {
         printf("エラー:n<=5となるnを入力してください\n");
         return (-1);
     }

     Input_matrix(X,Y,n);//行列の入力

     printf("k乗なるk(kは自然数)を入力してください");
     scanf("%d",&k);
     if(k<=0)
     {
    	 printf("エラー:kは自然数です");
    	 return(-1);
     }

     Multiply_matrix(X,X,Y,Z,n,k);//行列の計算

     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("行列Aの%d行%d列成分は…%f\n",i+1,j+1,Y[i][j]);
         }
     }
     return 0;
 }

これは行列のk乗(累乗)を求めるプログラムなんですが、k=1のときやkが4以上の時が計算結果があいません。
多分k=2、k=3のときしかあいません・・・><
どこがいけないんでしょうか?
まだ提出まで時間はあります。
なんかプログラムもだらだら長い気がします。しかしどう直せばいいのかわかりません・・・
なぜか家ではデバッグうまくいかないし・・・
どなたかお願いします><

box
記事: 2002
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#14

投稿記事 by box » 13年前

Multiply_matrix()の第4引数は、どこで初期化していますか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 2002
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#15

投稿記事 by box » 13年前

Input_matrix(X,Y,n);//行列の入力

第2引数は、「行列要素の入力」という観点からは不要のはずです。
Y[][]は、main()での定義時に初期化しておけばじゅうぶんでありましょう。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#16

投稿記事 by れお » 13年前

なるほどです!
初期化してないとはまだまだあまいですね・・・><
ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: またもや宿題でつまずいております・・・

#17

投稿記事 by h2so5 » 13年前

れお さんが書きました: ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;
すべて0で初期化する場合は、

float X[N][N] = {{0}};

という書き方ができます。

box
記事: 2002
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#18

投稿記事 by box » 13年前

コメントは入れてありませんし、ちゃんとテストしたわけでもありません。
課題の結果として提出する場合は、各文が何をしているかを人に説明できるように
しておいてください。

コード:

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

#define N (5)

void Input_matrix(double (*x)[N], int n)
{
    int i, j;

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("%d行%d列の要素=", i + 1, j + 1);
            scanf("%lf", &x[i][j]);
        }
    }
    putchar('\n');
}

void Print_matrix(double (*x)[N], int n)
{
    int i, j;

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("[%d][%d]=%f\n", i + 1, j + 1, x[i][j]);
        }
    }
    putchar('\n');
}

void Multiple_matrix(double (*x)[N], double (*y)[N], int n, int p)
{
    double z[N][N];
    int i, j, k, m, t = sizeof(double) * N * N;

    memcpy(z, x, t);
    for (k = 2; k <= p; k++) {
        memset(y, 0, t);
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
                for (m = 0; m < n; m++) {
                    y[i][j] += x[i][m] * z[m][j];
                }
            }
        }
        memcpy(z, y, t);
    }
    memcpy(y, z, t);
}

int main(void)
{
    double x[N][N], y[N][N];
    int n, p;

    do {
        printf("正方行列の行・列数は"), scanf("%d", &n);
    } while (n < 1 || N < n);
    Input_matrix(x, n);
    Print_matrix(x, n);
    do {
        printf("何乗しますか"), scanf("%d", &p);
    } while (p < 1);
    Multiple_matrix(x, y, n, p);
    Print_matrix(y, n);
    return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#19

投稿記事 by れお » 13年前

h2so5 さんが書きました:
れお さんが書きました: ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;
すべて0で初期化する場合は、

float X[N][N] = {{0}};

という書き方ができます。
そうなんですか!
勉強になります^^ありです^^
すべて1のときも同様にいけるんですよね??
最後に編集したユーザー れお on 2012年5月05日(土) 23:52 [ 編集 1 回目 ]

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#20

投稿記事 by れお » 13年前

box さんが書きました:コメントは入れてありませんし、ちゃんとテストしたわけでもありません。
課題の結果として提出する場合は、各文が何をしているかを人に説明できるように
しておいてください。

コード:

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

#define N (5)

void Input_matrix(double (*x)[N], int n)
{
    int i, j;

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("%d行%d列の要素=", i + 1, j + 1);
            scanf("%lf", &x[i][j]);
        }
    }
    putchar('\n');
}

void Print_matrix(double (*x)[N], int n)
{
    int i, j;

    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("[%d][%d]=%f\n", i + 1, j + 1, x[i][j]);
        }
    }
    putchar('\n');
}

void Multiple_matrix(double (*x)[N], double (*y)[N], int n, int p)
{
    double z[N][N];
    int i, j, k, m, t = sizeof(double) * N * N;

    memcpy(z, x, t);
    for (k = 2; k <= p; k++) {
        memset(y, 0, t);
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
                for (m = 0; m < n; m++) {
                    y[i][j] += x[i][m] * z[m][j];
                }
            }
        }
        memcpy(z, y, t);
    }
    memcpy(y, z, t);
}

int main(void)
{
    double x[N][N], y[N][N];
    int n, p;

    do {
        printf("正方行列の行・列数は"), scanf("%d", &n);
    } while (n < 1 || N < n);
    Input_matrix(x, n);
    Print_matrix(x, n);
    do {
        printf("何乗しますか"), scanf("%d", &p);
    } while (p < 1);
    Multiple_matrix(x, y, n, p);
    Print_matrix(y, n);
    return 0;
}
課題提出の際floatを用いるなど指定があるので、これを提出できないのでさんこうにさせていただきます^^
ありがとうございました^^b

今確認したところ、習っていないものが結構でてきていて理解できません・・・><
行列計算のところです。。。
僕のコードを訂正してもらえないでしょうか?こちらでも今奮闘中ですが・・・

ちなみに貴方のコードは正常にうごいていて、結果も正しいです。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#21

投稿記事 by れお » 13年前

コード:

//n×n正方行列Aに対して、Aのk乗を求めるプログラム
 #include <stdio.h>
 #define N 5

 void Input_matrix(float (*X)[N],int n)   //2次元配列のポインタ。後ろのほうしか必要じゃない
 {
     int i=0,j=0;
     for(i=0;i<n;i++)
     {
         for(j=0;j<n;j++)
         {
             printf("行列Aの%d行%d列成分の値を入力してください\n",i+1,j+1);
             scanf("%f",&X[i][j]);
         }
     }

     return ;
 }


 void Multiply_matrix(float (*X)[N],float (*Y)[N],float (*Z)[N],float (*W)[N],int n,int k)
 {
     int h=0,i=0,j=0,p=0;
     if(k==1)
     {
         for(i=0;i<n;i++)
         {
             for(j=0;j<n;j++)
             {
                 Y[i][j]=X[i][j];
             }
         }
    	 return;
     }
     else
     {
    	 for(i=0;i<n;i++)
    	 {
    		 for(j=0;j<n;j++)
    		 {
    			 for(p=0;p<n;p++)
    			 {
    				 Z[i][j]+=X[i][p]*Y[p][j];//Zを初期化しないと計算があわない;
    			 }
    		 }
    	 }
    	 if(k==2)
    	 {
    		 return;
    	 }
    	 else//累乗
    		 {
				 for(h=2;h<k;h++)
				 {
					 for(i=0;i<n;i++)
					 {
						 for(j=0;j<n;j++)
						 {
							 for(p=0;p<n;p++)
							 {
								 W[i][j]+=Z[i][p]*Y[p][j];
							 }
						 }
					 }
					 for(i=0;i<n;i++)
					 {
						 for(j=0;j<n;j++)
						 {
							 Z[i][j]=W[i][j];
						 }
					 }
				 }
    		 }
    	 return;
     }
 }

 void Print_matrix(float (*Y)[N], int n)
 {
     int i=0, j=0;
     for (i = 0; i < n; i++) {
         for (j = 0; j < n; j++) {
             printf("[%d][%d]=%f\n", i + 1, j + 1, Y[i][j]);
         }
     }
     return;
 }



 int main(void)
 {
     float X[N][N]={{0}},Y[N][N]={{0}},Z[N][N]={{0}};//初期化しないと行列計算の時おかしくなる
     int n=0,k=0;
     printf("n(<=5)を決めてください。n=");
     scanf("%d",&n);

     if(n>5)
     {
         printf("エラー:n<=5となるnを入力してください\n");
         return (-1);
     }

     Input_matrix(X,n);//行列の入力

     printf("k乗なるk(kは自然数)を入力してください\n[行][列]\n");
     scanf("%d",&k);
     if(k<=0)
     {
    	 printf("エラー:kは自然数です");
    	 return(-1);
     }

     Multiply_matrix(X,X,Y,Z,n,k);//行列の計算

     Print_matrix(Y, n);

     return 0;
 }
初期化しましたがやはり計算結果があいません。
k=1だと計算結果、行列の全要素が0。
2,3ではうまくいきますが、4以上だとあいません><

boxさんのを見ても自分のどこがいけないのかわかりませんでした・・・

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#22

投稿記事 by れお » 13年前

k=1のときはできました。
関数内のYをZとしなければいけませんでした。

kが4以上のときがまだむりです><
わかるかた教えてください・・・

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#23

投稿記事 by れお » 13年前

いけました。
69行目の後にW[j]=0;
とするのをわすれてました。というか気づいてませんでした。
これをしないとどんどんたされてしまうんですね。
解決しました。
回答してくださったかたがたありがとうございます!!^^

かずま

Re: またもや宿題でつまずいております・・・

#24

投稿記事 by かずま » 13年前

れお さんが書きました:いけました。
69行目の後にW[j]=0;
とするのをわすれてました。というか気づいてませんでした。
これをしないとどんどんたされてしまうんですね。

69行目の後ではなく、59行目の前に W[j] = 0; を入れると、main で Z の初期化が要らなくなります。
X や Y の初期化も不要です。初期化した値は使っていませんよね。

コード:

int i = 0, j = 0;
for (i = 0; ... 
これも変です。for の最初で初期化するのだから、宣言時の初期化は不要です。
Multiply_matrix が 4つの行列を引数にとるのも気になります。
作業用の行列 W は関数内に持つほうがよいでしょう。

ということで、書き直してみました。

コード:

// n×n正方行列Aに対して、Aのk乗を求めるプログラム
#include <stdio.h>
#include <stdlib.h>

#define N 5

void Input_matrix(float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("行列Aの%d行%d列成分の値を入力してください\n", i+1, j+1);
            if (scanf("%f", &X[i][j]) != 1) {
                printf("不正入力です\n");
                exit(1);
            }
        }
    }
}

// Y = X の k 乗
void Power_matrix(float X[][N], float Y[][N], int n, int k)
{
    int h, i, j, p;
    float W[N][N];
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            Y[i][j] = X[i][j];
        }
    }
    for (h = 1; h < k; h++) {
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
                W[i][j] = 0;
                for (p = 0; p < n; p++) {
                    W[i][j] += Y[i][p] * X[p][j];
                }
            }
        }
        for (i = 0; i < n; i++) {
            for (j = 0; j < n; j++) {
                Y[i][j] = W[i][j];
            }
        }
    }
}

void Print_matrix(float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            printf("[%d][%d]=%f\n", i + 1, j + 1, X[i][j]);
        }
    }
}

int main(void)
{
    float X[N][N], Y[N][N];
    int n, k;

    printf("n (<=5) を決めてください。n=");
    if (scanf("%d", &n) != 1 || n > 5) {
        printf("エラー:n<=5 となる n を入力してください\n");
        return 1;
    }
    Input_matrix(X, n);//行列の入力
    printf("k乗なる k(k は自然数)を入力してください\n[行][列]\n");
    if (scanf("%d", &k) != 1 || k <= 0) {
        printf("エラー:k は自然数です");
        return 1;
    }
    Power_matrix(X, Y, n, k);
    Print_matrix(Y, n);
    return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: またもや宿題でつまずいております・・・

#25

投稿記事 by みけCAT » 13年前

コード:

    if (scanf("%d", &n) != 1 || n > 5) {
        printf("エラー:n<=5 となる n を入力してください\n");
        return 1;
    }
どうせなら、nが0以下の場合もチェックしたらどうですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#26

投稿記事 by れお » 13年前

たしかにそうですね。忘れてましたww>みけCATさん
あぁいうのは初期化しないほうがいいんですか?意味ないのはわかってるんですが、一応初期化してたんですが・・・>かずまさん

ちなみに今回のは行列をコピーしてk乗の計算をしていますが、コピーせずにやろうとおもったらどうすればいいんですかね?
ポインタを利用するみたいなんですが・・・
自分が考えたのは2乗の計算をする関数をk乗する関数のどこかにいれればいけるような気がしたんですが、なんかイメージがつかめず、どこにその関数を挿入すれバいいかわかりませn;

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: またもや宿題でつまずいております・・・

#27

投稿記事 by beatle » 13年前

かずま さんが書きました:

コード:

int i = 0, j = 0;
for (i = 0; ... 
これも変です。for の最初で初期化するのだから、宣言時の初期化は不要です。
変数宣言時に必ず初期化する、というのはあながち間違いという訳ではないと思います。
不要ですが、やってはいけない訳ではなく、これはこれでアリな戦略だと思います。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#28

投稿記事 by れお » 13年前

りょーかいです^^

かずま

Re: またもや宿題でつまずいております・・・

#29

投稿記事 by かずま » 13年前

れお さんが書きました: ちなみに今回のは行列をコピーしてk乗の計算をしていますが、コピーせずにやろうとおもったらどうすればいいんですかね?
ポインタを利用するみたいなんですが・・・
k > 1 の場合はコピーしないプログラムです。

コード:

#include <stdio.h>
#include <stdlib.h>
 
#define N 5
 
void Input_matrix(float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++) {
            printf("行列Aの%d行%d列成分の値を入力してください\n", i+1, j+1);
            if (scanf("%f", &X[i][j]) != 1) printf("不正入力です\n"), exit(1);
        }
}
 
// Y = X の k 乗
void Power_matrix(const float X[][N], float Y[][N], int n, int k)
{
    int h, i, j, p;
    if (k == 1) {
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                Y[i][j] = X[i][j];
    } else {
        const float (*a)[N] = X;    
        float W[N][N], (*b)[N] = (k & 1) ? W : Y;
        for (h = 1; h < k; h++) {
            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++) {
                    float t = 0;
                    for (p = 0; p < n; p++)
                        t += a[i][p] * X[p][j];
                    b[i][j] = t;
                }
            }
            if (b == W) a = W, b = Y;
            else        a = Y, b = W;
        }
    }
}
 
void Print_matrix(const float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            printf("[%d][%d]=%f\n", i + 1, j + 1, X[i][j]);
}
 
int main(void)
{
    float X[N][N], Y[N][N];
    int n, k;
 
    printf("n (<=5) を決めてください。n=");
    if (scanf("%d", &n) != 1 || n <= 0 || n > 5)
        printf("エラー:n<=5 となる n を入力してください\n"), exit(1);
    Input_matrix(X, n);
    printf("k乗なる k(k は自然数)を入力してください\n[行][列]\n");
    if (scanf("%d", &k) != 1 || k <= 0)
        printf("エラー:k は自然数です"), exit(1);
    Power_matrix(X, Y, n, k);
    Print_matrix(Y, n);
    return 0;
}

かずま

Re: またもや宿題でつまずいております・・・

#30

投稿記事 by かずま » 13年前

X の k乗では (k-1)回の掛け算が必要ですが、
ちょっと工夫して掛け算の回数を減らしてみました。
例えば、k = 10 のとき、次のように 4回の掛け算で済みます。

 X * X → W    : W = X^2
 W * W → Y   : Y = X^4
 Y * X → W    : W = X^5
 W * W → Y   :- Y = X^10

コード:

#include <stdio.h>
#include <stdlib.h>
 
#define N 5
 
void Input_matrix(float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++) {
            printf("行列Aの%d行%d列成分の値を入力してください\n", i+1, j+1);
            if (scanf("%f", &X[i][j]) != 1) printf("不正入力です\n"), exit(1);
        }
}
 
// Z = X * Y
void Multiply_matrix(const float X[][N], const float Y[][N], float Z[][N], int n)
{
    int i, j, p;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            float t = 0;
            for (p = 0; p < n; p++)
                t += X[i][p] * Y[p][j];
            Z[i][j] = t;
        }
    }
}

// Y = X の k 乗
void Power_matrix(const float X[][N], float Y[][N], int n, int k)
{
    float W[N][N];
    if (k == 1) {
        int i, j;
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
                Y[i][j] = X[i][j];
    } else if (k == 2) {
        Multiply_matrix(X, X, Y, n);
    } else if (k == 3) {
        Multiply_matrix(X, X, W, n);
        Multiply_matrix(W, X, Y, n);
    } else if (k & 1) {  // 奇数
        Power_matrix(X, Y, n, k >> 1);
        Multiply_matrix(Y, Y, W, n);
        Multiply_matrix(W, X, Y, n);
    } else {             // 偶数
        Power_matrix(X, W, n, k >> 1);
        Multiply_matrix(W, W, Y, n);
    }
}
 
void Print_matrix(const float X[][N], int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            printf("[%d][%d]=%f\n", i + 1, j + 1, X[i][j]);
}
 
int main(void)
{
    float X[N][N], Y[N][N];
    int n, k;
 
    printf("n (<=5) を決めてください。n=");
    if (scanf("%d", &n) != 1 || n <= 0 || n > 5)
        printf("エラー:n<=5 となる n を入力してください\n"), exit(1);
    Input_matrix(X, n);//行列の入力
    printf("k乗なる k(k は自然数)を入力してください\n[行][列]\n");
    if (scanf("%d", &k) != 1 || k <= 0)
        printf("エラー:k は自然数です"), exit(1);
    Power_matrix(X, Y, n, k);
    Print_matrix(Y, n);
    return 0;
}

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#31

投稿記事 by れお » 13年前

(k & 1)ってどういういみですか??;
あとexitってどういうときにつかうんですか?リターンとはちがうのですか?
もう寝ないと明日早いのでまた今度詳しくみてみます

ありがとうございますほんとに・・・

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: またもや宿題でつまずいております・・・

#32

投稿記事 by beatle » 13年前

&はC言語の演算子の一つで、「ビット積」をする演算子です。ビット演算は結構ハードウェア寄りな話です。いろいろなサイトで解説されています。
exitは普通のリターンとは違いますが、main関数で使うreturnとはほぼ同じ意味です。
一般の関数でreturnすると、その関数の呼び出し元に戻るだけでプログラムは終了しませんがexitならプログラムが終了します。

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#33

投稿記事 by れお » 13年前

なんかポインタのポインタを利用しないといけないみたいなんです><
(**p)みたいなやつです。。。

かずま

Re: またもや宿題でつまずいております・・・

#34

投稿記事 by かずま » 13年前

k = 1 のときもコピーしないようにしました。
Power_matrix には、結果の帰る場所を 2つ与えることにし、
実際に結果の入ったところへのポインタを返します。

コード:

#include <stdio.h>
#include <stdlib.h>
 
#define N 5

typedef float (*Matrix)[N];
 
void Input_matrix(Matrix X, int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++) {
            printf("行列Aの%d行%d列成分の値を入力してください\n", i+1, j+1);
            if (scanf("%f", &X[i][j]) != 1) printf("不正入力です\n"), exit(1);
        }
}
 
// Z = X * Y
void Multiply_matrix(Matrix X, Matrix Y, Matrix Z, int n)
{
    int i, j, p;
    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            float t = 0;
            for (p = 0; p < n; p++)
                t += X[i][p] * Y[p][j];
            Z[i][j] = t;
        }
    }
}

// X の k 乗 を X, Y, Z のいずれかに入れ、それを返す
Matrix Power_matrix(Matrix X, Matrix Y, Matrix Z, int n, int k)
{
    if (--k <= 0) return X;      // k が 1 のとき
    Multiply_matrix(X, X, Y, n);
    while (--k > 0) {
        Multiply_matrix(Y, X, Z, n);
        if (--k == 0) return Z;  // k が奇数のとき
        Multiply_matrix(Z, X, Y, n);
    }
    return Y;                    // k が偶数のとき
}
 
void Print_matrix(Matrix X, int n)
{
    int i, j;
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            printf("[%d][%d]=%f\n", i + 1, j + 1, X[i][j]);
}
 
int main(void)
{
    float X[N][N], Y[N][N], Z[N][N];
    Matrix p;
    int n, k;
 
    printf("n (0<n<=5) を決めてください。n=");
    if (scanf("%d", &n) != 1 || n <= 0 || n > 5)
        printf("エラー:0<n<=5 となる n を入力してください\n"), exit(1);
    Input_matrix(X, n);//行列の入力
    printf("k乗なる k(k は自然数)を入力してください\n[行][列]\n");
    if (scanf("%d", &k) != 1 || k <= 0)
        printf("エラー:k は自然数です"), exit(1);
    p = Power_matrix(X, Y, Z, n, k);
    Print_matrix(p, n);
    return 0;
}
次は、乗算回数を減らしたものです。

コード:

// X の k 乗 を X, Y のいずれかに入れ、それを返す
Matrix Power_matrix(Matrix X, Matrix Y, Matrix Z, int n, int k)
{
    if (k == 1) return X;  // K が 1 の場合

    if (k & 1) {  // k は奇数
        Matrix p = Power_matrix(X, Y, Z, n, k >> 1);
        Multiply_matrix(p, p, Z, n);
        Multiply_matrix(Z, X, Y, n);
    } else {     // k は偶数
        Matrix p = Power_matrix(X, Z, Y, n, k >> 1);
        Multiply_matrix(p, p, Y, n);
    }
    return Y;  // k が 1 以外の場合
}

たいちう
記事: 418
登録日時: 14年前

Re: またもや宿題でつまずいております・・・

#35

投稿記事 by たいちう » 13年前

> すべて1のときも同様にいけるんですよね??

スルーされているような気がしますので、念のため。
0での初期化限定です。試してみて下さい。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: またもや宿題でつまずいております・・・

#36

投稿記事 by みけCAT » 13年前

ところで、同じ人が同じような内容の質問を複数のトピックで行うのは、あまりよくないと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

かずま

Re: またもや宿題でつまずいております・・・

#37

投稿記事 by かずま » 13年前

かずま さんが書きました: 次は、乗算回数を減らしたものです。

コード:

// X の k 乗 を X, Y のいずれかに入れ、それを返す
Matrix Power_matrix(Matrix X, Matrix Y, Matrix Z, int n, int k)
{
    if (k == 1) return X;  // K が 1 の場合

    if (k & 1) {  // k は奇数
        Matrix p = Power_matrix(X, Y, Z, n, k >> 1);
        Multiply_matrix(p, p, Z, n);
        Multiply_matrix(Z, X, Y, n);
    } else {     // k は偶数
        Matrix p = Power_matrix(X, Z, Y, n, k >> 1);
        Multiply_matrix(p, p, Y, n);
    }
    return Y;  // k が 1 以外の場合
}
このアルゴリズムは、最小の乗算回数を求めるものではありません。

例えば、k = 15 のとき、次のように 乗算回数 6 となります。

 X * X → Z  : Z = X^2
 Z * X → Y  : Y = X^3
 Y * Y → Z  : Z = X^6
 Z * X → Y  : Y = X^7
 Y * Y → Z  : Z = X^14
 Z * X → Y  : Y = X^15

ところが X^15 は乗算回数 5 で求めることができます。

 X * X → Y  : Y = X^2
 Y * Y → Z  : Z = X^4
 Z * X → Y  : Y = X^5
 Y * Y → Z  : Z = X^10
 Z * Y → X  : X = X^15

れお
記事: 113
登録日時: 13年前

Re: またもや宿題でつまずいております・・・

#38

投稿記事 by れお » 13年前

すみません。
これは一度解決にしてしまったので・・・
こっちはもう流すつもりだったのですが・・・
まだみなさん見てくれているようで結果またあがってしまいました。

kが奇数偶数でわけるのもなしという課題で、ポインタノポインタを用いる課題だったのですが、自分が理解できていないため、もう条件には反してコピーで提出することにします。
みなさんありがとうございました。

閉鎖

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