現代応用解析 B レポート

G98P010-2 石川 隼輔

平成 13 年 6 月 4 日

1 演習 3

課題 前回の電卓プログラムで行列を扱えるようにする

一応行列計算部分は実装したが、行列の要素の値に計算式を使うことや、変数に行列をいれることなどまでは実装しなかった。

行列同士の、加算、減算、乗算とスカラとの乗算とマイナスを実装した。

2 プログラムソース

3 mfcalc.h

#include <stdio.h>
#define LINE_SIZE 50
#define COLUMN_SIZE 50
typedef struct _line
{
double nColumns[COLUMN_SIZE];
int nSize;
} line;
typedef struct _matrix
{
line nLines[LINE_SIZE];
int nLineSize;
int nColumnSize;
} matrix;

typedef struct _symrec
{
  char *name;
  int type;
  union {
    double var;
    double (*fnctptr)();
  } value;
  struct _symrec *next;
} symrec;
typedef struct _init
{
  char *fname;
  double (*fnct)();
} init;
symrec *putsym (char* sym_name, int sym_type);
symrec *getsym (char* sym_name);
int yylex(void);
int yyerror(char* s);
int init_table (void);
int init_matrix(matrix *pMatrix);
int init_line(line *pLine);
int addNum(line *pLine, double nNumber);
int addLine(matrix *pMatrix, line *pLine);
int copyMatrix(matrix *pMatrix1, const matrix *pMatrix2);
int addMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *matrix2);
int minusMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *matrix2);
int multiplyMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *matrix2);
int multiplyConstant(matrix *pMatrix, double nConstant);
int printMatrix(const matrix* pMatrix1);

4 mfcalc.y

%{

#include <math.h>
#include "mfcalc.h"
init arith_fncts[] = {
      "sin", sin,
      "cos", cos,
      "acos", acos,
      "atan", atan,
      "ln", log,
      "exp", exp,
      "sqrt", sqrt,
      0, 0
};
symrec *sym_table = 0;
/******************************************
*
* For Matrix Code
*
*/
int init_line(line *pLine)
{
  int i = 0;
  pLine->nSize = 0;
  for(i=0; i<COLUMN_SIZE; i++)
    pLine->nColumns[i] = 0;
  return 1;
}
int init_matrix(matrix *pMatrix)
{
  int i = 0;
  pMatrix->nLineSize = 0;
  pMatrix->nColumnSize = 0;
  for(i=0; i<LINE_SIZE; i++)
    init_line(&pMatrix->nLines[i]);
  return 1;

}
int addNum(line *pLine, double nNumber)
{
pLine->nColumns[pLine->nSize] = nNumber;
pLine->nSize += 1;
return 1;
}
int addLine(matrix *pMatrix, line *pLine)
{
pMatrix->nColumnSize = pLine->nSize;
pMatrix->nLines[pMatrix->nLineSize] = *pLine;
pMatrix->nLineSize++;
return 1;
}
int copyMatrix(matrix *pMatrix1, const matrix *pMatrix2)
{
int i = 0, j = 0;
init_matrix(pMatrix1);
for(i=0; i<pMatrix2->nLineSize; i++)
  for(j=0; j<pMatrix2->nColumnSize; j++)
    pMatrix1->nLines[i].nColumns[j] = pMatrix2->nLines[i].nColumns[j];
pMatrix1->nLineSize = pMatrix2->nLineSize;
pMatrix1->nColumnSize = pMatrix2->nColumnSize;
return 1;
}
int addMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *pMatrix2)
{
int i = 0, j = 0;
init_matrix(pMatrix);
if(pMatrix1->nLineSize != pMatrix2->nLineSize ||
    pMatrix1->nColumnSize != pMatrix2->nColumnSize)
    return 0;
pMatrix->nLineSize = pMatrix1->nLineSize;

pMatrix->nColumnSize = pMatrix1->nColumnSize;
for(i=0; i<pMatrix1->nLineSize; i++)
  for(j=0; j<pMatrix1->nColumnSize; j++)
    pMatrix->nLines[i].nColumns[j] = pMatrix1->nLines[i].nColumns[j] + pMatrix2->nLines[i].nColumns[j];
return 1;
}
int minusMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *pMatrix2)
{
int i = 0, j = 0;
init_matrix(pMatrix);
if(pMatrix1->nLineSize != pMatrix2->nLineSize ||
    pMatrix1->nColumnSize != pMatrix2->nColumnSize)
    return 0;
pMatrix->nLineSize = pMatrix1->nLineSize;
pMatrix->nColumnSize = pMatrix1->nColumnSize;
for(i=0; i<pMatrix1->nLineSize; i++)
  for(j=0; j<pMatrix1->nColumnSize; j++)
    pMatrix->nLines[i].nColumns[j] = pMatrix1->nLines[i].nColumns[j] - pMatrix2->nLines[i].nColumns[j];
}
int multiplyMatrix(matrix *pMatrix, const matrix *pMatrix1, const matrix *pMatrix2)
{
int i = 0, j = 0, k = 0;
init_matrix(pMatrix);
if(pMatrix1->nColumnSize != pMatrix2->nLineSize)
  return 0;
pMatrix->nColumnSize = pMatrix1->nLineSize;
pMatrix->nLineSize = pMatrix2->nColumnSize;
for(i=0; i<pMatrix1->nLineSize; i++)
  for(j=0; j<pMatrix1->nColumnSize; j++)
    for(k=0; k<pMatrix1->nColumnSize; k++)
      pMatrix->nLines[i].nColumns[j] += pMatrix1->nLines[i].nColumns[k] * pMatrix2->nLines[k].nColumns[j];

return 1;
}
int multiplyConstant(matrix *pMatrix, double nConstant)
{
int i = 0, j = 0;
for(i=0; i<pMatrix->nLineSize; i++)
  for(j=0; j<pMatrix->nColumnSize; j++)
    pMatrix->nLines[i].nColumns[j] = pMatrix->nLines[i].nColumns[j] * nConstant;
return 1;
}
int printMatrix(const matrix* pMatrix)
{
int i = 0, j = 0;
for(i=0; i<pMatrix->nLineSize; i++) {
  printf("| ");
  for(j=0; j<pMatrix->nColumnSize; j++)
     printf("%f ", pMatrix->nLines[i].nColumns[j]);
  printf("|\n");
}
return 1;
}
symrec *putsym (char* sym_name, int sym_type)
{
symrec *ptr;
ptr = (symrec *) malloc (sizeof (symrec));
ptr->name = (char *) malloc (strlen (sym_name) + 1);
strcpy (ptr->name,sym_name);
ptr->type = sym_type;
ptr->value.var = 0; /* 関数の場合にも値を 0 にする */
ptr->next = sym_table;
sym_table = ptr;
return ptr;
}

symrec *getsym (char* sym_name)
{
  symrec *ptr;
  for (ptr = sym_table; ptr != (symrec *) 0;
       ptr = (symrec *)ptr->next)
    if (strcmp (ptr->name,sym_name) == 0)
      return ptr;
  return 0;
}
int yyerror (char* s)
{
  printf ("%s\n", s);
}
int init_table (void)  /* 数学関数を表に登録する */
{
  int i;
  symrec *ptr;
  for (i = 0; arith_fncts[i].fname != 0; i++)
    {
      ptr = putsym (arith_fncts[i].fname, FNCT);
      ptr->value.fnctptr = arith_fncts[i].fnct;
    }
}
%}
%union {
double val;
symrec *tptr;
matrix  *matrix;
line    *line;
};
%token <val>  NUM
%token <tptr> VAR FNCT
%type  <val>  exp
%type  <line> number.list

%type  <line> matrix.member
%type  <matrix> matrix.member.list
%type  <matrix> matrix
%type  <matrix> matrix.exp
%right '='
%left '-' '+'
%left '*' '/'
%left NEG
%right '^'
%%
input : /* empty */
        | input line
;
line : '\n'
        | exp '\n'   { printf ("\t%.10g\n", $1); }
| matrix.exp '\n'
{
  printMatrix($1);
  free($1);
}
        | error '\n' { yyerrok;                  }
;
exp     : NUM                { $$ = $1;                         }
        | VAR                { $$ = $1->value.var;              }
        | VAR '=' exp        { $$ = $3; $1->value.var = $3;     }
        | FNCT '(' exp ')'   { $$ = (*($1->value.fnctptr))($3); }
        | exp '+' exp        { $$ = $1 + $3;                    }
        | exp '-' exp        { $$ = $1 - $3;                    }
        | exp '*' exp        { $$ = $1 * $3;                    }
        | exp '/' exp        { $$ = $1 / $3;                    }
        | '-' exp  %prec NEG { $$ = -$2;                        }
        | exp '^' exp        { $$ = pow ($1, $3);               }
        | '(' exp ')'        { $$ = $2;                         }
;

matrix.exp : matrix  { $$ = $1; }
| matrix.exp '+' matrix.exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(addMatrix($$, $1, $3) == 0) {
free($1);
free($3);
yyerror("matrix error");
  }
  else {
free($1);
free($3);
  }
}
| matrix.exp '-' matrix.exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(minusMatrix($$, $1, $3) == 0) {
free($1);
free($3);
yyerror("matrix error");
  }
  else {
free($1);
free($3);
  }
}
| matrix.exp '*' matrix.exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(multiplyMatrix($$, $1, $3) == 0) {
free($1);
free($3);
yyerror("matrix error");
  }
  else {
free($1);
free($3);

  }
}
| matrix.exp '*' exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(multiplyConstant($1, $3) == 0)
yyerror("matrix error");
  else
    $$ = $1;
}
| exp '*' matrix.exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(multiplyConstant($3, $1) == 0)
yyerror("matrix error");
  else
    $$ = $3;
}
| '-' matrix.exp
{
  $$ = (matrix*)malloc(sizeof(matrix));
  if(multiplyConstant($2, -1) == 0)
yyerror("matrix error");
  else
    $$ = $2;
}
| '(' matrix.exp ')'
{
  $$ = $2;
}
;
matrix : '[' matrix.member.list ']'
{
  $$ = $2;
}
;
matrix.member.list  : matrix.member

{
  $$ = (matrix*)malloc(sizeof(matrix));
  init_matrix($$);
  addLine($$, $1);
  free($1);
}
| matrix.member.list matrix.member
{
  addLine($1, $2);
  $$ = $1;
  free($2);
}
;
matrix.member : '(' number.list ')'
{
  $$ = $2;
}
;
number.list : NUM
{
  $$ = (line*)malloc(sizeof(line));
  init_line($$);
  addNum($$, $1);
}
| number.list NUM
{
  addNum($1, $2);
  $$ = $1;
}
;
%%
YYSTYPE yylval;
int yylex(void)
{

int c;
while ((c = getchar ()) == ' ' || c == '\t');
if (c == EOF)
return 0;
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", &yylval.val);
return NUM;
}
if (isalpha (c))
{
symrec *s;
static char *symbuf = 0;
static int length = 0;
int i;
if (length == 0)
  length = 40, symbuf = (char *)malloc (length + 1);
i = 0;
do
  {

/* あふれたのでバッファを大きくする */

    if (i == length)
      {
        length *= 2;
        symbuf = (char *)realloc (symbuf, length + 1);
      }

/* 文字をバッファに変える */

    symbuf[i++] = c;

/* 次の文字を読む */

    c = getchar ();
  }
while (c != EOF && isalnum (c));

      ungetc (c, stdin);
      symbuf[i] = '\0';
      s = getsym (symbuf);
      if (s == 0)
        s = putsym (symbuf, VAR);
      yylval.tptr = s;
      return s->type;
    }
  return c;
}
int main(void)
{
init_table();
yyparse();
return 0;
}

5 考察

Ｃ＋＋で実装したかったのだが、 bison のはいたコードは関数宣言などをしっかり行っていないようでうまくコンパイルできなかった。

時間ができたら、変数の使用なども可能にできるように改造したいと思う。