質問するログイン新規登録

質問編集履歴

2

アルゴリズムの修正。説明を追加。作り直したソースコードを張りました。

2017/02/13 11:00

投稿

inxsirencer
inxsirencer

スコア16

title CHANGED
File without changes
body CHANGED
@@ -2,92 +2,148 @@
2
2
  Cで行列のランク計算をするプログラムを作っています。
3
3
 
4
4
  プログラムの流れは、
5
- 1.行列の行数、列数を入力
5
+ 1.行列の行数(lnum)、列数(cnum)を入力
6
6
  2.行列の各成分を入力、格納。
7
- 3.ij列の成分が0ならば、n[i]=0,非0ならばn[i]=1格納。これをj列の成分すべてについて行う。
7
+ 3行列の走査(matsearch)を行う。
8
- 4.i₀≦i≦[行数の総数]とする。n[i]=1ならば、i行成分をすべて(i,j)成分で割り、n[i]=0ならば割らずに次の列に移動を繰り返し、すべての列でこれが完了すると、i[i]=1である行iのみに対して、i行-i₀行の行基本変形を行う。それを終えると、j+1列に移って、i₀+1行以降の行について4.の操作を繰り返す。
9
- 5.↑の操作を行うにあたって、(i₀,j)成分が0であった場合にはi₀行以降の(i,j)成分でn[i]=1の成分があれば、そのような行をi₁行として、i₀行+i₁行の行基本変形を行う。そして、4.の操作をおこなう。
10
- 6.5.を満たすような成分がない(i₀行以降のj列成分すべて0の)場合、j+1行に移って4.操作をうが、この時、その操作はi₀+1行から開始するのはなく、i₀行から開始する。
8
+ 走査範囲初めは1列目行であるとする。
9
+ 1列目から順に
10
+ 特定の列の走査範囲内の要素をを上から順に確認
11
+ →すべて0 ⇒ 走査範囲はそのままで次の列に
11
12
 
13
+ →上端が非0かつ上端以外はすべて0 ⇒ 走査範囲を一つ縮める(元の走査範囲から上端の行を抜いたもの)。そして走査範囲は次の列へ
14
+
15
+ →上端以外に非0が存在
16
+ ⇒ その列が基本変形対象範囲最重要列J₀
17
+ かつ
18
+ その走査範囲の上端の行は基本変形対象範囲開始行I₀。
19
+ for行ループ → break
20
+ for列ループ → break
21
+ matsearch → 終了
22
+
23
+ 最終的に…matsearchの返却値は
24
+ ①J=cnumですべてその列の成分が0
25
+ → -2
26
+ ②(I₀,J₀)=0かつbreak
27
+ → I₀
28
+ ③(I₀,J₀)≠0かつbreak
29
+ → -1
30
+ 4.行基本変形
31
+ ①:
32
+ rank計算へ
33
+
34
+ ②:
35
+ (I, J₀)成分のうち、I₀≦I≦lnumの範囲で
36
+ 非0となっている成分について考える。
37
+ このような成分のうち、最小行番号をもつ成分の行番号
38
+ をI₁とする。(I₀<I₁≦lnum)
39
+
40
+ 2-2-1.1:(I₁,J)成分でI₁行成分をすべて割る。
41
+ 2-2-1.2:(I₀,J)成分に
42
+ 「(I₀,J)成分 + (I₁,J)成分」
43
+ の演算結果を代入する。
44
+ 2-2-1.3:
45
+ (I,J)成分に(I>I₀)
46
+ 「(I,J)成分 -{(I,J)成分*(I₀,J)}」
47
+ の演算結果を代入する。
48
+ そのまま③へ
49
+
50
+ ③:
51
+ 操作2-1
52
+ 2-1.1:(I₀ , J₀)成分でI₀行成分をすべて割る。
53
+ 2-1.2:(I,J)成分に(I>I₀)
54
+ 「(I,J)成分 -{(I,J)成分*(I₀,J)}」
55
+ の演算結果を代入する。
56
+
57
+
12
58
  という手順を踏んで行基本変形を行う予定だったのですが、この手順通りに操作がいかないです。
13
59
 
14
60
  どうかよろしくおねがいいいたします。
15
61
  ###発生している問題・エラーメッセージ
16
- 例えば、計算過程で
17
- | 1.00 2.00 3.00 |
18
- | 0.00 1.00 2.00 |
19
- | 0.00 0.00 0.00 |
20
- ここまているので、もう何も余計ことをする必要はなのに、
62
+ 計算過程ループが終了せずどこが間違っているのかがわからないです。
21
- 次の手順後には
22
- | 1.00 2.00 3.00 |
23
- | 0.00 1.00 2.00 |
24
- | 0.00 0.00 1.00 |
25
- と訳の分からないことをしています。
26
63
 
27
64
 
28
65
  ###該当のソースコード
29
- ```ここに言語を入力
66
+ ```
30
67
  #include <stdio.h>
68
+ #define NA 7
69
+ #define NB 3
70
+ #define PLUS 0
71
+ #define MINUS 1
72
+ #define ERROR_R 1.000000e-15
31
73
 
32
- #define numa 3
33
- #define numb 7
34
- #define plus 0
35
- #define minus 1
36
74
 
37
- /*四捨五入(10のn乗の位を処理)*/
38
- #include <math.h>
39
-
40
- double around(double src, int n)
75
+ int zerojudgef(double a)
41
76
  {
42
- double dst;
43
-
44
- dst = src * pow(10, -n - 1); /*処理を行う桁を10-1 の位にする*/
45
- dst = (double)(int)(dst + 0.5);
46
-
47
- return dst * pow(10, n + 1); /*処理を行った桁を元に戻す*/
77
+ return ((a < ERROR_R) & (a > (-1)*ERROR_R) ? 0 : 1);
48
78
  }
49
79
 
50
- /**/
51
- int line, column = 0;
52
- /**/
80
+ int matsearchf(double mat[][NA][NA], int lnum, int cnum, int keylinenum, int keycolumnnum, int rank)
81
+ /*
82
+ keylinenum : the number of line that is the start point of elementary row operation. Exactly, in the column of key-column number, and below the line of the start line of elemntary row operation ,there may exists the element that is not zero which has the smallest number of line. The line number of such elements is defined as keylinenum.
83
+ That is, if the start line of elementary row operation is not the exactly defined keyline number, the start line of elementray row operation is linebreak.
53
84
 
54
- double mat[numa][numb][numb];
85
+ keycolumnnum : the number of column that is the key-column of elementary row op
55
-
56
- int zerojudgef(double a)
86
+ ertion.
87
+ */
57
88
  {
89
+ int i, j;
90
+ int linebreak = 0;
91
+ for(j=0; j<cnum; j++){
92
+ int k = 0;
93
+ int notzero = 0;
58
- return (a != 0 ? 1 : 0);
94
+ int keynum_for_count = 0;
59
- }
95
+ for(i=linebreak; i<lnum; i++){
60
96
 
61
- void substif(int n[], double mat[0][numb][numb], int i, int lnum)
62
- {
63
- /*i : 1 or 0 判定を行う列番号*/
64
- /*lnum : 行数の総数*/
65
- int h;
66
- double a;
67
- for(h=0; h<lnum; h++){
68
- a = mat[0][h][i];
69
- n[h] = zerojudgef(a);
70
- }
97
+ if(zerojudgef(mat[0][i][j])){
98
+ notzero++;
99
+ }/*for-for-if*/
100
+ }/*for-for*/
101
+ /*Finding out the key-line number
102
+ In the column of key-column number, and below the line of key-line number, there may exists the element that is not zero which has the smallest number of line. The line number of such elements is defined as keylinenum, and in this function, for the purpose of counting the key-line number, a variable 'keynum_for_count' is defined.
103
+ */
104
+ do{
105
+ keynum_for_count = (zerojudgef(mat[0][k][j]) != 0 ? k : -1);//ここは最悪k+linebreakでもok
106
+ k++;
107
+ }while( (keynum_for_count < 0) & (k != (NA-1) ) );//matのイランとこは全部0で初期化が条件
71
108
 
72
- /**/
73
- puts("substif");
109
+ if(zerojudgef(notzero)){/*There exist at least one element that is not equal to zero.*/
110
+
74
- printf("\n");
111
+ if(zerojudgef(mat[0][linebreak][j])){/*The top elements in the scope of line-searching is not equal to zero.*/
112
+ if(notzero > 1){/*There exists not-zero elemnet at the top of the scope of line searching, and exists not-zero elements below the elements at the top. break roop*/
75
- for(line=0; line<numb; line++){
113
+ keylinenum = keynum_for_count;
76
- printf("|");
77
- for(column=0; column<numb; column++){
78
- printf("%6.f", mat[0][line][column]);
79
- }
80
- printf(" |\n");
81
- }
82
- printf("\n\n");
114
+ keycolumnnum = j;
115
+ return -1;
116
+ break;
117
+ }else{
118
+ /*There exists not-zero element only at the top of the searching range, and elements below it is all equal to zero. continue roop*/
119
+ linebreak++;
83
120
 
121
+ }/*for-if-if-if*/
122
+ }else{/*The top elements in the scope of line-searching is equal to zero, but there exist at least one elements that is not equal to zero. break roop*/
84
- for(line=0; line<numb; line++)
123
+ keylinenum = keynum_for_count;
124
+ keycolumnnum = j;
125
+ return linebreak;
126
+ break;
127
+ }/*for-if-if*/
85
- printf("n[%d] %5d\n", line, n[line]);
128
+ }else{/*There exist only elements that is equal to zero. continue roop*/
129
+
86
-
130
+ }/*for-if*/
87
- /**/
131
+ }/*for*/
132
+
133
+ rank = linebreak;
134
+ return -2;
135
+
136
+ /*Finally, the result is classified into 3 types.
137
+ 1:All the elemnets in the last column of the scope is equal to zero.
138
+ output = -2
139
+ 2:The (keylinenum, keycolumnnum) elemnet is equal to zero.
140
+ output = linebreak
141
+ 3:The (keylinenum, keycolumnnum) elemnet is not equal to zero.
142
+ output = -1
143
+ */
88
144
  }
89
145
 
90
- void divf(int divdo, int divdonel, int cnum, double mat[0][numb][numb])
146
+ void divf(int divdo, int divdonel, int cnum, double mat[][NA][NA])
91
147
  {
92
148
  /*
93
149
  divdo :割る数の要素の列番号
@@ -98,16 +154,16 @@
98
154
 
99
155
  int i;
100
156
  for(i=0; i<cnum; i++){
101
- double divided = mat[0][divdonel][i];
102
- mat[0][divdonel][i] = around(divided / divisor, -5);
157
+ mat[0][divdonel][i] /= divisor;
103
158
  }
104
159
 
105
160
  /**/
161
+ int line, column;
106
- puts("divf");
162
+ puts("divf");
107
163
  printf("\n");
108
- for(line=0; line<numb; line++){
164
+ for(line=0; line<NA; line++){
109
165
  printf("|");
110
- for(column=0; column<numb; column++){
166
+ for(column=0; column<NA; column++){
111
167
  printf("%5.2f", mat[0][line][column]);
112
168
  }
113
169
  printf(" |\n");
@@ -119,27 +175,29 @@
119
175
 
120
176
  }
121
177
 
122
- void subtraf(int p, int q, int r, int cnum, double mat[0][numb][numb])
178
+ void subtraf(int p, int q, int r, int cnum, double mat[][NA][NA], double coeff)
123
179
  {
124
180
  /*
125
- p ± q行 を行う。
181
+ This function operates the line p ± the line q.
126
- r = 0 or 1
182
+ Judge by whether r = 0 or 1
127
- -r=0→足し算
183
+ -r=0→addition
128
- -r=1→引き算
184
+ -r=1→subtraction
129
- cnum = 行列の総列数
185
+ cnum = The total number of line
186
+ coeff = the coefficient of the number that subtacts any numbers
130
187
  */
131
188
  int pm = (r == 1 ? (-1) : 1);
132
189
  int i;
133
190
  for(i=0; i<cnum; i++){
134
- mat[0][p][i] += (pm * mat[0][q][i]);
191
+ mat[0][p][i] += (coeff * pm * mat[0][q][i]);
135
192
  }
136
193
 
137
194
  /**/
195
+ int line, column;
138
- puts("subtraf");
196
+ puts("subtraf");
139
197
  printf("\n");
140
- for(line=0; line<numb; line++){
198
+ for(line=0; line<NA; line++){
141
199
  printf("|");
142
- for(column=0; column<numb; column++){
200
+ for(column=0; column<NA; column++){
143
201
  printf("%5.2f", mat[0][line][column]);
144
202
  }
145
203
  printf(" |\n");
@@ -152,233 +210,95 @@
152
210
 
153
211
  }
154
212
 
155
-
156
- void divjudgef(int e, int k, int cnum, int lnum, double mat[0][numb][numb], int n[])
213
+ void erowoperatef(double mat[][NA][NA], int lnum, int cnum, int keylinenum, int keycolumnnum)
157
214
  {
158
- /*
159
- e :行基本変形の対象範囲の左上角の成分の行番号
160
- k :行基本変形対象範囲の左上角の成分の列番号
215
+ int rank = 0;
161
- cnum :行列の総行数
216
+ int i, j, k;
162
- lnum :行列の総列数
217
+ int breakjudge = 0;
163
- */
218
+ for(i=0; i<NA; i++){
164
-
165
- int u = 0;/*e以降のeに対する相対的な行番号e+uはa_e_k以降初めての非0の成分の存在する業番号を表す。*/
219
+ k = ( ( matsearchf(mat, lnum, cnum, keylinenum, keycolumnnum, rank) < 0 ) ? matsearchf(mat, lnum, cnum, keylinenum, keycolumnnum, rank) : 1 );
166
-
167
- switch(n[e] == 0){
220
+ switch(k){
168
- /*1:The pattern of A_e_k = 0*/
169
- case 1:{
170
- while(n[e+u] == 0){
171
- u++;
172
- if((e+u) == lnum){
173
- break;
174
- }/*switch-case1-while-if*/
175
- break;
176
- }/*switch-case1-while*/
177
-
178
- switch((e+u) == lnum){
179
-
180
- /*The pattern of 1-1:A_e_* = 0(All zero)*/
181
221
  case 1:{
182
- e -= 1;
183
- printf("%d\n", e);
222
+ divf(keycolumnnum, keylinenum, cnum, mat);
184
- break;
223
+ subtraf( matsearchf(mat, lnum, cnum, keylinenum, keycolumnnum, rank), keylinenum, PLUS, cnum, mat, 1);
185
- }/*switch-case1-switch-case1*/
224
+ }/*for-switch-case0*/
186
-
187
- /*The pattern of 1-2:There exists at least one elemnets such as A_e_* ≠ 0*/
188
- case 0:{
225
+ case -1:{
189
- divf(k, e+u, cnum, mat);
226
+ divf(keycolumnnum, keylinenum, cnum, mat);
227
+ if(i = keylinenum){
228
+ }else{
229
+ for(j=0; j<lnum; j++){
190
- subtraf(e, e+u, plus, cnum, mat);
230
+ subtraf( j, keylinenum, MINUS, cnum, mat , mat[0][j][keycolumnnum]);
231
+ }/*for-switch-case-1-if-for*/
232
+ }/*for-switch-case-1-if*/
191
233
  break;
192
- }/*switch-case1-switch-case0*/
193
- }/*switch-case1-switch*/
234
+ }/*for-switch-case1*/
235
+ case -2:{
236
+ breakjudge = 1;
194
- break;
237
+ break;
195
- }/*switch-case1*/
238
+ }/*for-switch-case-1*/
196
-
197
- /*The pattern of 2:A_e_k ≠ 0*/
239
+ }/*switch*/
198
- case 0:{
199
- for(u=0; u<lnum; u++){
200
- switch(n[e+u] == 1){
240
+ if(breakjudge == 1){
201
-
202
- /*The pattern of 2-2:A_e_p ≠ 0*/
203
- case 1:{
204
- divf(k, e+u, cnum, mat);
205
- break;
206
- }/*switch-case0-for-switch-case1*/
207
-
208
- /*The pattern of 2-1:A_e_p = 0*/
209
- case 0:{
210
241
  break;
211
- }/*switch-case0-for-switch-case0*/
212
- }/*switch-case0-for-switch*/
242
+ }/*for-if*/
213
- }/*switch-case0-for*/
243
+ }/*for*/
214
244
 
215
- break;
216
- }/*switch-case0*/
217
-
218
- }/*switch*/
219
-
220
- /**/
221
- puts("divjudgef");
222
- printf("\n");
223
- for(line=0; line<numb; line++){
224
- printf("|");
225
- for(column=0; column<numb; column++){
226
- printf("%5.2f", mat[0][line][column]);
227
- }
228
- printf(" |\n");
229
- }
230
- printf("\n\n");
231
-
232
-
233
- /**/
234
-
235
-
236
245
  }
237
246
 
238
-
239
-
240
-
241
- int rankcalf(double mat[0][numb][numb], int lnum, int cnum)
247
+ int rankcaloperatef(double mat[][NA][NA], int lnum, int cnum)
242
248
  {
243
-
249
+ int keylinenum = 0;
250
+ int keycolumnnum = 0;
251
+ erowoperatef(mat, lnum, cnum, keylinenum, keycolumnnum);
244
252
  int rank = 0;
245
- int i,j;
246
- for(i=0; i<lnum; i++){
247
- for(j=0; j<numb; j++){
248
- if(mat[0][i][j] == 1){
249
- if(j != numb-1){
250
- rank++;
251
- break;
252
- }/*'j = numb-1' means the last column number of the matrix and its elements is a sentinel.*/
253
-
254
- }
255
- }
256
- }
257
-
258
- /**/
259
- puts("rankcalf");
260
- printf("\n");
261
- for(line=0; line<numb; line++){
262
- printf("|");
263
- for(column=0; column<numb; column++){
264
- printf("%5.2f", mat[0][line][column]);
253
+ int empty = matsearchf(mat, lnum, cnum, keylinenum, keycolumnnum, rank);
265
- }
266
- printf(" |\n");
267
- }
268
- printf("\n\n");
269
-
270
-
271
- /**/
272
-
273
-
274
254
  return rank;
275
-
276
255
  }
277
256
 
278
- int rankopf(double mat[0][numb][numb], int lnum, int cnum, int n[])
257
+ int main(void)
279
258
  {
280
- /*
281
- We'll use substif and then use for sentence to apply dvijudgef to each column.
282
- In the for sentence, operation continues as follows.:
283
- After applying divjudgef to a particular column, the situation will be A or B.
284
- The element that is located in the upper-left side in the scope of elementary rows operations
285
- is
286
- A : 1
287
- B : 0.
288
- subtraf operation will be applied to the type A.
289
- nothing will be done to the type B.
259
+ double mat[NB][NA][NA] = {};
290
- */
291
- int i = 0;/*for controling line row*/
260
+ int lnum, cnum;
292
- int j = 0;/*for controling column row*/
261
+ /*mat[kind of matrix][line number][column number] */
262
+ puts("\nWe will calculate the rank of a matrix.\nPlease enter the scale of matrix.");
263
+ printf("The number of lines (under %d) = ", NA);
264
+ scanf("%d", &lnum);
265
+ printf("The number of columns (under %d) = ", NA);
266
+ scanf("%d", &cnum);
267
+ puts("Please enter the elements of the matrix.");
268
+ puts("'mat[i][j]' represents the (i,j) elements of the matrix.");
269
+ int i, j;
293
270
  for(i=0; i<lnum; i++){
294
- int detallzero = i;
271
+ for(j=0; j<cnum; j++){
272
+ printf("mat[%d][%d] = ", i+1, j+1);
273
+ scanf("%lf", &mat[0][i][j]);
295
- substif(n, mat, j, lnum);
274
+ mat[1][i][j] = mat[0][i][j];
275
+ }
276
+ }
277
+ /*mat[1]にはもともと行列が保存される。*/
296
- divjudgef(i, j, cnum, lnum, mat, n);
278
+ int Rank = rankcaloperatef(mat, lnum, cnum);
297
- if(detallzero == i){
298
- int k;
279
+ int r;
299
- for(k=i+1; k<lnum; k++){
280
+ for(r=0; r<2; r++){
300
- if(n[k] != 0){
301
- subtraf(k, i, minus, cnum, mat);
302
- }/*for-if-for-if*/
303
- }/*for-if-for*/
304
- }/*for-if*/
305
- j++;
306
- }/*for*/
307
-
308
- /*The operation above are all 'Elementary rows operations of matrix',
309
- and then, we will calculate the rank of the matrix.*/
310
-
311
- /**/
312
- puts("rankopf");
313
- printf("\n");
281
+ printf("\n");
314
- for(line=0; line<numb; line++){
315
- printf("|");
316
- for(column=0; column<numb; column++){
317
- printf("%5.2f", mat[0][line][column]);
318
- }
319
- printf(" |\n");
320
- }
321
- printf("\n\n");
322
-
323
-
324
- /**/
325
-
326
-
327
-
328
- return rankcalf(mat, lnum, cnum);
329
- }
330
-
331
- int main(void)
332
- {
333
-
334
- int lnum, cnum;
335
- /*mat[kind of matrix][line number][column number] */
336
-
337
- puts("\nWe will calculate the rank of a matrix.\nPlease enter the scale of matrix.");
338
- printf("The number of lines (under %d) = ", numb);
339
- scanf("%d", &lnum);
340
- printf("The number of columns (under %d) = ", numb);
341
- scanf("%d", &cnum);
342
-
343
- puts("Please enter the elements of the matrix.");
344
- puts("'mat[i][j]' represents the (i,j) elements of the matrix.");
345
-
346
- int i, j;
347
- for(i=0; i<numb; i++){
348
- mat[0][i][numb-1] = 1;
349
- }/*Rendering mat[0][i][numb-1] sentinel for the rank calcularation.*/
350
-
351
282
  for(i=0; i<lnum; i++){
283
+ printf("|");
352
284
  for(j=0; j<cnum; j++){
353
- printf("mat[0][%d][%d] = ", i+1, j+1);
354
- scanf("%lf", &mat[0][i][j]);
285
+ printf("%5.f", mat[r][i][j]);
355
- mat[1][i][j] = mat[0][i][j];
356
286
  }
287
+ printf(" |\n");
357
288
  }
358
- /*mat[1]にはもともと行列が保存される。*/
359
- int n[numb];
289
+ printf("\n\n");
290
+ }
360
- int rank = rankopf(mat, lnum, cnum, n);
291
+ printf("\nThe rank of this matrix is %d.\n", Rank);
292
+ return 0;
361
293
 
362
- int r;
363
- for(r=0; r<2; r++){
364
- printf("\n");
365
- for(i=0; i<lnum; i++){
366
- printf("|");
367
- for(j=0; j<cnum; j++){
368
- printf("%5.f", mat[r][i][j]);
369
- }
294
+ }
370
- printf(" |\n");
371
- }
372
- printf("\n\n");
373
- }
374
295
 
375
- printf("\nThe rank of this matrix is %d.\n", rank);
376
296
 
377
- return 0;
378
- }
379
297
 
380
298
  ```
381
299
 
382
300
 
383
301
  ###試したこと
384
- 上のソースコードのなかで、2つの/**/で挟まれたprintf …の部分は演算過程を見るために付け加えたものです。いくつかのデバッグは自己解決できたのですが、これに関してはわからないです。
302
+ 上のソースコードのなかで、2つの/**/で挟まれたprintf …の部分は演算過程を見るために付け加えたものです。いくつかのデバッグは自己解決できたのですが、これに関してはわからないです。
303
+
304
+ 又、初めのアルゴリズムでは欠陥があったので、少し変えて作り直しました。

1

「試したこと」を記入しました。

2017/02/13 11:00

投稿

inxsirencer
inxsirencer

スコア16

title CHANGED
File without changes
body CHANGED
@@ -377,4 +377,8 @@
377
377
  return 0;
378
378
  }
379
379
 
380
- ```
380
+ ```
381
+
382
+
383
+ ###試したこと
384
+ 上のソースコードのなかで、2つの/**/で挟まれたprintf …の部分は演算過程を見るために付け加えたものです。いくつかのデバッグは自己解決できたのですが、これに関してはわからないです。