ページ 1 / 1
またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 00:14
by れお
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初心者から脱していないのでできるだけ訂正箇所、理由など詳しくお願いしたいです・・・><
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 00:26
by box
コードを全部見たわけではないですが、ぱっと見で気づいた点を…。
れお さんが書きました:
コード:
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回ループしたいときの書き方で、こういうのはめずらしいと思います。ちょっと見かけたことがないですね。
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 00:31
by れお
!?
ありがとうございます!!
内側にいれる必要がありますね^^
ちょっと今忙しいので確認できないかもですが。それは確実です。
ありがとうございます^^
他にもあればお願いします・・・><
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 00:36
by れお
確認しました^^
多分いけました^^
ここから任意の整数kにおけるAのk乗を求めるプログラムにかえたいので自力でちょっとがんばってみます。
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 17:39
by れお
コード:
//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
あきらかにおかしいです・・・
どこがおかしいのでしょうか??;
デバッグができないため確認もできません><
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 17:55
by みけCAT
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
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 18:05
by かずま
初期化されてない Y に、値をどんどん足しこんでいますよ。
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 18:06
by れお
宿題がfloat指定だったのでfloatのままやりましたが、やはり指摘どおり初期化してないからでした。ありがとうございました。
doubleとfloat・・・変えるだけでうまくいくなんてことあるんですね^^;違いを全然理解してないもので;
とりあえずおかげさまで解決いたしましたので、提出したらk乗に挑戦します。
ありがとうございました。^^
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 18:13
by れお
k乗にいくまえに・・・^^;
float *p[ ] と float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
なんで*p[ ] だとうまくいかないんでしょう・・・・
pは自分のコードでいうXやYなどにあたります
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 18:38
by box
れお さんが書きました:
float *p[ ] と float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
前者は、「pはポインターの配列である」ことを意味します。
後者は、「pは配列へのポインターである」ことを意味します。
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 18:41
by ISLe
れお さんが書きました:float *p[ ] と float (*p)[ ] の2つの変数宣言の違いについてどう違うのか簡単におしえていただけませんか?
float *p[]
float*型を要素に持つ配列。
p[0]~p[n]それぞれがfloatを指すポインタです。
float (*p)[]
float型を要素に持つ配列を指すポインタ。
p自体は配列ではなくひとつの要素を指します。
Re: またもや宿題でつまずいております・・・
Posted: 2012年4月30日(月) 19:02
by れお
OKです^^
助かります!!
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 17:04
by れお
コード:
//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のときしかあいません・・・><
どこがいけないんでしょうか?
まだ提出まで時間はあります。
なんかプログラムもだらだら長い気がします。しかしどう直せばいいのかわかりません・・・
なぜか家ではデバッグうまくいかないし・・・
どなたかお願いします><
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 17:52
by box
Multiply_matrix()の第4引数は、どこで初期化していますか?
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 18:14
by box
Input_matrix(X,Y,n);//行列の入力
第2引数は、「行列要素の入力」という観点からは不要のはずです。
Y[][]は、main()での定義時に初期化しておけばじゅうぶんでありましょう。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 20:10
by れお
なるほどです!
初期化してないとはまだまだあまいですね・・・><
ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 20:35
by h2so5
れお さんが書きました:
ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;
すべて0で初期化する場合は、
float X[N][N] = {{0}};
という書き方ができます。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 20:56
by 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;
}
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 23:48
by れお
h2so5 さんが書きました:れお さんが書きました:
ところで初期化っていちいちループまわして初期化するしかないんですかね??^^;
すべて0で初期化する場合は、
float X[N][N] = {{0}};
という書き方ができます。
そうなんですか!
勉強になります^^ありです^^
すべて1のときも同様にいけるんですよね??
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月05日(土) 23:49
by れお
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
今確認したところ、習っていないものが結構でてきていて理解できません・・・><
行列計算のところです。。。
僕のコードを訂正してもらえないでしょうか?こちらでも今奮闘中ですが・・・
ちなみに貴方のコードは正常にうごいていて、結果も正しいです。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月06日(日) 00:36
by れお
コード:
//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さんのを見ても自分のどこがいけないのかわかりませんでした・・・
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月06日(日) 02:41
by れお
k=1のときはできました。
関数内のYをZとしなければいけませんでした。
kが4以上のときがまだむりです><
わかるかた教えてください・・・
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月06日(日) 02:49
by れお
いけました。
69行目の後にW[j]=0;
とするのをわすれてました。というか気づいてませんでした。
これをしないとどんどんたされてしまうんですね。
解決しました。
回答してくださったかたがたありがとうございます!!^^
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月07日(月) 02:51
by かずま
れお さんが書きました:いけました。
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;
}
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月07日(月) 21:13
by みけCAT
コード:
if (scanf("%d", &n) != 1 || n > 5) {
printf("エラー:n<=5 となる n を入力してください\n");
return 1;
}
どうせなら、nが0以下の場合もチェックしたらどうですか?
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月09日(水) 21:58
by れお
たしかにそうですね。忘れてましたww>みけCATさん
あぁいうのは初期化しないほうがいいんですか?意味ないのはわかってるんですが、一応初期化してたんですが・・・>かずまさん
ちなみに今回のは行列をコピーしてk乗の計算をしていますが、コピーせずにやろうとおもったらどうすればいいんですかね?
ポインタを利用するみたいなんですが・・・
自分が考えたのは2乗の計算をする関数をk乗する関数のどこかにいれればいけるような気がしたんですが、なんかイメージがつかめず、どこにその関数を挿入すれバいいかわかりませn;
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月09日(水) 22:25
by beatle
かずま さんが書きました:コード:
int i = 0, j = 0;
for (i = 0; ...
これも変です。for の最初で初期化するのだから、宣言時の初期化は不要です。
変数宣言時に必ず初期化する、というのはあながち間違いという訳ではないと思います。
不要ですが、やってはいけない訳ではなく、これはこれでアリな戦略だと思います。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月10日(木) 22:12
by れお
りょーかいです^^
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月10日(木) 22:28
by かずま
れお さんが書きました:
ちなみに今回のは行列をコピーして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: またもや宿題でつまずいております・・・
Posted: 2012年5月11日(金) 00:03
by かずま
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;
}
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月11日(金) 00:43
by れお
(k & 1)ってどういういみですか??;
あとexitってどういうときにつかうんですか?リターンとはちがうのですか?
もう寝ないと明日早いのでまた今度詳しくみてみます
ありがとうございますほんとに・・・
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月11日(金) 07:04
by beatle
&はC言語の演算子の一つで、「ビット積」をする演算子です。ビット演算は結構ハードウェア寄りな話です。いろいろなサイトで解説されています。
exitは普通のリターンとは違いますが、main関数で使うreturnとはほぼ同じ意味です。
一般の関数でreturnすると、その関数の呼び出し元に戻るだけでプログラムは終了しませんがexitならプログラムが終了します。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月11日(金) 19:17
by れお
なんかポインタのポインタを利用しないといけないみたいなんです><
(**p)みたいなやつです。。。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月12日(土) 02:32
by かずま
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 以外の場合
}
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月12日(土) 08:13
by たいちう
> すべて1のときも同様にいけるんですよね??
スルーされているような気がしますので、念のため。
0での初期化限定です。試してみて下さい。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月12日(土) 15:47
by みけCAT
ところで、同じ人が同じような内容の質問を複数のトピックで行うのは、あまりよくないと思います。
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月13日(日) 11:55
by かずま
かずま さんが書きました:
次は、乗算回数を減らしたものです。
コード:
// 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
Re: またもや宿題でつまずいております・・・
Posted: 2012年5月13日(日) 18:54
by れお
すみません。
これは一度解決にしてしまったので・・・
こっちはもう流すつもりだったのですが・・・
まだみなさん見てくれているようで結果またあがってしまいました。
kが奇数偶数でわけるのもなしという課題で、ポインタノポインタを用いる課題だったのですが、自分が理解できていないため、もう条件には反してコピーで提出することにします。
みなさんありがとうございました。