- 締切済み
演算対象の数字と演算子を入力して計算させる
数字と演算子をそれぞれ入力し、優先順位の高い順に四則演算させるにはどのような考え方をすればよいのでしょうか。 数字をa[7]とおいて、演算子をop[7]としてそれぞれ配列に格納しましたが、そこから先に進めません。 オペランドと演算子の組み合わせならば優先順に計算してくれるのはわかっていますが、オペランドと演算子を格納した配列では上手く行きません。 実は既に全ての演算子の組み合わせをIfで表示させるプログラムを根性で作ったのですが、最適解を知りたいです。 言語はCでvisualstudioを使っております。 条件はn回数字を入力したらn-1回演算子を入力し、n回目に=を入力する。nの最大値は7とする。です。 だらだらと見辛い文章で申し訳ありませんが、何卒宜しくお願いします。
- みんなの回答 (8)
- 専門家の回答
みんなの回答
- maru_yoshi_
- ベストアンサー率39% (17/43)
> だめだめじゃん > 自分 > 乗除が続いたときうまくいかない。 ということで、修正しました。 int* pLeft = &a[0]; for (int i = 0; i < sizeof(op)/sizeof(op[0]); ++i) { switch (op[i]) { case '*': *pLeft *= a[i+1]; break; case '/': *pLeft /= a[i+1]; break; default: pLeft = &a[i+1]; break; } } int result = a[0]; for (int i = 0; i < sizeof(op)/sizeof(op[0]); ++i) { switch (op[i]) { case '+': result += a[i+1]; break; case '-': result -= a[i+1]; break; default: break; } } こんなんでいかがでしょう。 最適とは言えないでしょうけど... 優先度グループが二つしかないから2回のループ、グループが3つなら3回のループになるけど、 3回のループを回すなら、構文解析ツリーにくみなおす方がきれいかな。
- maru_yoshi_
- ベストアンサー率39% (17/43)
だめだめじゃん > 自分 乗除が続いたときうまくいかない。
- maru_yoshi_
- ベストアンサー率39% (17/43)
>優先順位の高い順に四則演算させるには 四則演算は加減乗除で、その中で優先順位があるは加減と乗除で乗除を先に行う必要があるだけ。 簡単に考えれば、一回目のループで乗除を行い、二回目のループで加減を行えばよい。 一回目の演算結果は演算子の左側に残しておく。 二回目のループでは有効な演算の右側のオペランドを順次演算していく。 実際のプログラムは以下の通り。 int a[] = {1, 2, 3, 4, 5, 6, 7}; char op[] = {'+', '*', '-', '/', '+', '*'}; for (int i = 0; i < sizeof(op)/sizeof(op[0]); ++i) { switch (op[i]) { case '*': a[i] *= a[i+1]; break; case '/': a[i] /= a[i+1]; break; default: break; } } int result = a[0]; for (int i = 0; i < sizeof(op)/sizeof(op[0]); ++i) { switch (op[i]) { case '+': result += a[i+1]; break; case '-': result -= a[i+1]; break; default: break; } } printf("Result = %d", result);
- uyama33
- ベストアンサー率30% (137/450)
コンパイラコンパイラを使って構文解析ルーチンを作る。 参考文献:coco 構文解析 で検索してください。 以下のコードは、数式をエクセルのように扱うために作成したものです。 これから、コンパイラコンパイラを使って、構文解析ルーチンを作成します。 -- Attribute grammar of s -- ==================================================== GRAMMAR s SEMANTIC DECLARATIONS --===================== TERMINALS --=========== NUM --1 CELL --2 FUNC --3 "+" --4 "-" --5 "*" --6 "/" --7 "^" --8 "(" --9 ")" --10 ":" --11 nococosy --12 NONTERMINALS --============= s e t f x u o --=========== Scanner rules ================= RULES s = e sem if(isformula) {*att = FORMULA;} else {*att = VALUE;} push(&curtoken); break; endsem. e = t {"+" sem push(&curtoken); break; endsem t sem token1 = pop(); curtoken.x.value += token1.x.value; break; endsem |"-" sem push(&curtoken); break; endsem t sem token1 = pop(); curtoken.x.value = token1.x.value - curtoken.x.value ; break; endsem}. t = f {"*" sem push(&curtoken); break; endsem f sem token1 = pop(); curtoken.x.value *= token1.x.value; break; endsem |"/" sem push(&curtoken); break; endsem f sem token1 = pop(); if (curtoken.x.value == 0) curtoken.x.value = HUGE_VAL; else curtoken.x.value = token1.x.value/curtoken.x.value;; break; endsem}. f = x ["^" sem push(&curtoken); break; endsem f sem token1 = pop(); curtoken.x.value = pow( token1.x.value, curtoken.x.value,); break; endsem ]. x = u | "-"u sem curtoken.x.value = -curtoken.x.value; break; endsem. u = CELL sem curtoken.x.value = cellvalue(curtoken.x.c.col, curtoken.x.c.row); break; endsem [ ":" sem push(&curtoken); break; endsem CELL sem push(&curtoken); token1 = pop(); token2 = pop(); curtoken.x.value = 0; if (token1.x.c.row == token2.x.c.row) { if (token1.x.c.col < token2.x.c.col) error = TRUE; else { for (counter = token2.x.c.col; counter <= token1.x.c.col; counter++) curtoken.x.value += cellvalue(counter, token1.x.c.row); } } else if (token1.x.c.col == token2.x.c.col) { if (token1.x.c.row < token2.x.c.row) error = TRUE; else { for (counter = token2.x.c.row; counter <= token1.x.c.row; counter++) curtoken.x.value += cellvalue(token1.x.c.col, counter); } } else error = TRUE; break; endsem ] | o. o = "("e")" | NUM | FUNC"(" sem push(&curtoken); break; endsem e sem token1 = pop(); if (strcmp(token1.x.funcname, "ABS") == 0) curtoken.x.value = fabs(curtoken.x.value); else if (strcmp(token1.x.funcname, "ACOS") == 0) curtoken.x.value = acos(curtoken.x.value); else if (strcmp(token1.x.funcname, "ASIN") == 0) curtoken.x.value = asin(curtoken.x.value); else if (strcmp(token1.x.funcname, "ATAN") == 0) curtoken.x.value = atan(curtoken.x.value); else if (strcmp(token1.x.funcname, "COSH") == 0) curtoken.x.value = cosh(curtoken.x.value); else if (strcmp(token1.x.funcname, "COS") == 0) curtoken.x.value = cos(curtoken.x.value); else if (strcmp(token1.x.funcname, "EXP") == 0) curtoken.x.value = exp(curtoken.x.value); else if (strcmp(token1.x.funcname, "LOG10") == 0) curtoken.x.value = log10(curtoken.x.value); else if (strcmp(token1.x.funcname, "LOG") == 0) curtoken.x.value = log(curtoken.x.value); else if (strcmp(token1.x.funcname, "ROUND") == 0) curtoken.x.value = (int)(curtoken.x.value + 0.5); else if (strcmp(token1.x.funcname, "POW10") == 0) curtoken.x.value = pow10(curtoken.x.value); else if (strcmp(token1.x.funcname, "SINH") == 0) curtoken.x.value = sinh(curtoken.x.value); else if (strcmp(token1.x.funcname, "SIN") == 0) curtoken.x.value = sin(curtoken.x.value); else if (strcmp(token1.x.funcname, "SQRT") == 0) curtoken.x.value = sqrt(curtoken.x.value); else if (strcmp(token1.x.funcname, "SQR") == 0) curtoken.x.value *= curtoken.x.value; else if (strcmp(token1.x.funcname, "TANH") == 0) curtoken.x.value = tanh(curtoken.x.value); else if (strcmp(token1.x.funcname, "TAN") == 0) curtoken.x.value = tan(curtoken.x.value); else if (strcmp(token1.x.funcname, "TRUNC") == 0) curtoken.x.value = (int)curtoken.x.value; break; endsem ")". ENDGR
- 麻野 なぎ(@asano_nagi)
- ベストアンサー率35% (42/120)
> オペランドと演算子の組み合わせならば優先順に計算してくれるのはわかっていますが これを、具体的にはどのようにして実現しているのか興味があります。 この方法が理解できていれば、「配列でも同じようにすればOKです」というのが、本来の回答なのですが。 あと、 > 実は既に全ての演算子の組み合わせをIfで表示させるプログラムを根性で作った ということですが、四則演算(括弧無し)なら、優先順位は2つしかありません。 なので、「すべての演算子の組み合わせ」ではなくて、 ・op とは別に、「優先順序」の配列を作る ・優先順序の組み合わせを網羅したプログラムを書く とすれば、とりあえず、複雑さは半減するはずです。
- Tacosan
- ベストアンサー率23% (3656/15482)
どういう入力に対してどういう結果になることを期待しているのかがわからんなぁ.
- kmee
- ベストアンサー率55% (1857/3366)
最適では無いかもしれませんが、一般には式の構造を解析して「木」構造や、逆ポーランド記法等の「順番に処理できる」形にします。 抽象構文木 http://home.a00.itscom.net/hatada/c-tips/ast/ast01.html とりあえず、検索で上位にあったものを一つ書きますが、より詳しい説明もあると思うので、探してみてください。
- asuncion
- ベストアンサー率33% (2127/6289)
>数字をa[7]とおいて、演算子をop[7]として 演算子はop[6]でいいのでは? 四則演算で、乗除を加減より優先して演算する際の 一つのやり方として、逆ポーランド記法を使うことが 考えられます。 例: 簡単のため、数値を5個、演算子を4個とします。 1 + 2 × 3 - 4 ÷ 5 = 6.2 左辺を逆ポーランド記法で記述すると、 1 2 3 × + 4 5 ÷ - 読み方は 1に、2に3をかけた結果を足し、4を5で割った結果を引く 見事に日本語の語順と対応していますね。