行列演算

ファイルもしくは標準入力から2つの行列を読み込み、その積を求めるプログラムです。

行列演算list_26.c)
/*
  mat_calc.c : for 崖っぷち大学生
  ・m×n 行列 A と標準入力から,行列 A の行数 m [1:100] を整数で入力.
  ・標準入力から,行列 A の列数 (行列 B の行数) n [1:100] を整数で入力.
  ・標準入力から,行列 B の列数 p [1:100] を整数で入力してもらう.
  ・標準入力から,m×n 行列 A の成分を入力,その成分を double 型の 2 次元配列に保存
  ・標準入力から,n×p 行列 B の成分を入力,その成分を double 型の 2 次元配列に保存.
  ・行列の成分の入力がすべて終わったら,行列 A と 行列 B の積 AB を計算し表示.
  */
#include <stdio.h>
#include <varargs.h>

#define STD_IN  "<stdin>"  // 標準入力

///////////////////////////////////////////////////////
void myprint(char* ifile,const char *va_alist,...);
void mxm(double *A,double *B,double* C,int m,int n,int p);
///////////////////////////////////////////////////////

int main(int argc,char* argv[])
{
    FILE *ifp;
    char *ifile;
    int i,j,k;
    int m,n,p;       // matrix size
    double *A,*B,*C; // matrix
    
    if(argc >= 2){
        /* ファイルからのデータ入力 */
        if((ifp=fopen(argv[1],"r")) == NULL){
            printf("can't open file.\n");
            return 0;
        }
        ifile = argv[1];
    } else {
        /* 標準入力からのデータ入力 */
        ifp   = stdin; ifile = STD_IN;
    }
    myprint(ifile,"input m:"); fscanf(ifp,"%d",&m);//行-A
    myprint(ifile,"input n:"); fscanf(ifp,"%d",&n);//列-A,行-B
    myprint(ifile,"input p:"); fscanf(ifp,"%d",&p);//列-B
    
    /* データ領域確保 */
    A = (double*)calloc(m*n,sizeof(double));
    B = (double*)calloc(n*p,sizeof(double));
    C = (double*)calloc(m*p,sizeof(double));
    
    /* データ入力 */
    myprint(ifile,"matrix A:\n",m);
    for(i=0;i<m;i++)for(j=0;j<n;j++){
        myprint(ifile,"%d.%d:",i,j);
        fscanf(ifp,"%lf",(A+i*n+j));
    }
    myprint(ifile,"matrix B:\n",m);
    for(i=0;i<n;i++)for(j=0;j<p;j++){
        myprint(ifile,"%d.%d:",i,j);
        fscanf(ifp,"%lf",(B+i*p+j));
    }
    
    /* 逆行列の計算・表示 */
    mxm(A,B,C,m,n,p);
    printf("\nmatrix A:\n");
    for(i=0;i<m;i++){
        for(j=0;j<n;j++) printf("%lf ",*(A+i*n+j));
        printf("\n");
    }
    printf("\nmatrix B:\n");
    for(i=0;i<n;i++){
        for(j=0;j<p;j++) printf("%lf ",*(B+i*p+j));
        printf("\n");
    }
    printf("\nmatrix C=A*B:\n");
    for(i=0;i<m;i++){
        for(j=0;j<p;j++) printf("%lf ",*(C+i*p+j));
        printf("\n");
    }
    printf("\n");

    if(strcmp(STD_IN,"<stdin>")) fclose(ifp);
    free(A);free(B);free(C);
    return 0;
}

/* 入力が標準入力なら表示しない */
void myprint(char* ifile,const char *va_alist,...)
{
    va_list args;
    char *fmt;
    char print_fmt[256];
    /* 可変個引数の使用開始の呪文 */
    va_start(args);
    /* 文字列を整形する */
    fmt=va_arg(args, char *);
    vsprintf(print_fmt, fmt, args);
    /* 可変個引数の使用終了の呪文 */
    va_end(args);
    
    if(!strcmp(ifile,STD_IN)) fprintf(stdout,print_fmt);
}

/* Matrix Multiplication */
void mxm(double *A,double *B,double* C,int m,int n,int p)
{
    int i,j,k;
    for(k=0;k<m;k++) for(j=0;j<p;j++){
        double s=0.;
        for(i=0;i<n;i++) s+=*(A+k*n+i)*(*(B+i*p+j));
        *(C+k*p+j)=s;
    }
}
実行結果
標準入力より入力:

Gami[1366]% mat_calc
input m:2
input n:1
input p:2
matrix A:
0.0:1
1.0:1
matrix B:
0.0:1
0.1:1

matrix A:
1.000000
1.000000

matrix B:
1.000000 1.000000

matrix C=A*B:
1.000000 1.000000
1.000000 1.000000

Gami[1367]%


ファイルより入力:

Gami[1369]% cat mxm.dat
3 1 3

1 1 1

1 1 1
Gami[1370]% mat_calc.exe mxm.dat

matrix A:
1.000000
1.000000
1.000000

matrix B:
1.000000 1.000000 1.000000

matrix C=A*B:
1.000000 1.000000 1.000000
1.000000 1.000000 1.000000
1.000000 1.000000 1.000000

Gami[1371]%
inserted by FC2 system