プロが教えるわが家の防犯対策術!

以下のプログラムは電卓のプログラムです。
http://codepad.org/n47BkpXa
このプログラムの変数の宣言はあえてint型で行っています。
コレを変えずに上手く計算結果が出せるようにしたいのですが、どこを修正すれ良いですか?
ご指導お願いします。
・問題点
例:10/4*4などの最初に割り算が入ると計算結果がおかしくなってしまいます。
10/4*4=8 int型なので小数点が切り捨てられて結果が8になってしまいます。
コレをint型を使用して10になるようにしたいのですがご指導お願いします。
多分イメージではif文で(op=/)&&(op+1=*)が出たら掛け算を始めにするとかだと思います。

A 回答 (8件)

ANo.2, 7です。



ANo.7ではcalc関数を修正しない方が良いと言いましたが、
ちゃんと計算できるように追加コード部分を修正してみました。

修正箇所は
if((*op == '/') && (*(op + 1) == '*')){/*op='/'、op+1='*'が入った時*/
 *x = (*x) * (*(x + 2));
 printf("answer1 = %d\n",*x);
 *(x + 2) = *x / *(x + 1) ;
 printf("answer2 = %d\n",*(x + 2));
 return *x;
}
の部分です。これを
if((*op == '/') && (*(op + 1) == '*')){/*op='/'、op+1='*'が入った時*/
 *x = (*x) * (*(x + 2));
 printf("answer1 = %d\n",*x);
 *(x + 2) = *x / *(x + 1) ;
 printf("answer2 = %d\n",*(x + 2));
 // return文は不要
 // 以下5行が追加コード
 *x = 0;
 *(x + 1) = 0;
 x = x + 2;
 op = op + 2;
 continue;
}
と直すと上手くいきます
(インデントに全角スペースを使っているので注意して下さい)。

*x = 0や*(x + 1) = 0が必要な理由は、
calc関数内のswitch文で*x = 0が実行されている理由と同じなのですが、
何故このコードが必要なのかは分かりますか?

この修正をすれば10/4*4のように、
「わり算1回、かけ算1回を行う式」には上手く対応できます。
しかし10/4/5*5*4や10/4/5*4*5のように、
「わり算が2回以上連続して続いた後にかけ算がある式」には対応できません。
これは追加コードでは、隣り合うわり算、かけ算のみを処理しているのが原因です。
例えば10/4/5*5*4では/5と*5は追加コード部分でうまく処理されるのですが、
位置が離れている/4と*4は処理されません。

これで妥協するかどうかは質問者さんに任せます。
妥協したくないなら、このコードを更に修正するか、
あるいは別の方法を取る事になります。
    • good
    • 0

追加コードの部分にreturnがあります。


これではwhileループで全ての数を処理する前に
calc関数を抜けてしまいます。
計算結果がおかしくなるのはそのためだと思います。

こういう面倒なことがあるので、並び替えの処理は
calc関数の中でやらない方がいいと思います。

並び替えだけを行う関数を作り、main関数の中で
(1) 並び替え関数
(2) calc関数(mode =1)
(3) calc関数(mode =0)
の順番で関数を呼び出せば良いと思いますが…。
    • good
    • 0

掛け算を先にやったらオーバーフローの可能性があるんだけど, そこには目をつむるってのが理解できん.



たとえば, int が 32ビットの環境で
1000000 / 100001 * 100001
を計算すると掛け算を先にやっても割算を先にやっても「期待した結果」にはならないはずなんだけど, そんなんでいいのか?

この回答への補足

いいです。
高精度な計算結果は求めていません。
自分が途中まで出来たのを入れます。
条件分岐を入れてみましたが、最終的な結果はおかしくなってしまいます。
下記にソースを入れます。修正箇所を教えて頂けますか?
#include <stdio.h>
#include <stdlib.h>
/*
int check_num(int *x, char *op)
{
inti;
while(*op != '=') {
for(i=0; i<10; i++) {
x[i] == *(x + i);
if(*(op + i) == '='){
calc(x, op , 1);
}
}
}
}
*/
int calc(int *x, char *op, int mode) /* x=項、op=演算子、mode=0か1で処理を分岐*/
{
while (*op != '=') {/*opに'='が代入されるまで回す*/
if (mode==0) {/*mode=0の処理(mode=1で得た計算結果を最後に加算する)*/
*(x + 1) = *(x+1) + (*x);
x++;/*配列に入れられた値を更新*/
op++;/*'='が出されるまでopを更新*/
}
if (mode==1) {/*mode=1の処理(乗算、除算、減算を行って、計算結果を配列に入れる)*/
if((*op == '/') && (*(op + 1) == '*')) {/*op='/'、op+1='*'が入った時*/
*x = (*x) * (*(x + 2));
printf("answer1 = %d\n",*x);
*(x + 2) = *x / *(x + 1) ;
printf("answer2 = %d\n",*(x + 2));
return *x;
}
switch (*op) {
/*乗算*/
case '*':
*(x + 1) = (*x) * (*(x + 1));/*例:x+1=4(x)×2(x+1)*/
*x = 0;
break;
/*除算*/
case '/':
*(x + 1) = *x / *(x + 1);/*例:x+1=4(x)÷2(x+1)*/
*x = 0;
break;
/*減算*/
case '-':/*例:x+1=2×(-1)*/
*(x + 1) = *(x+1) * (-1);/*最後に加算を行うので値をマイナスにして配列に入れる*/
break;
}
x++;
op++;
}
}
return *x;
}

intmain(void)
{
int x[10];/* 項 */
char op[10];/* 演算子 */
int i;
while (1) {
printf("式を入力してください\n");
printf("例:1*2+5=enter \n");
printf("式:");
for (i = 0; i<10; i++) {/*10項まで計算可*/
scanf("%d %c", x + i, op + i);
if (*(op + i) == '=')/*op='='が代入されるまで回し続ける*/
break;
}
calc(x, op, 1);
printf("答え:%d\n", calc(x, op, 0));/*mode=0の処理へ移行(最後に加算をして結果を出力)*/
}
/* return 0;*/
}

補足日時:2011/07/22 13:18
    • good
    • 0

>割り算と掛け算の順序を逆転させるという、


>数式解析のむずかしい技を使ってまで
>int型にこだわる理由が全くわかりません。
>講師の方がこういう課題を出してきました。結構、天邪鬼なかたなので。

まともなプログラマなら少数または分数処理するものを、整数にこだわる講師はまともでありません。講師本人の知識を披露したいだけのバカです。
この手のくだらない事に頭を使わずに、学校に抗議して講師を変えてもらったほうが良いです。
    • good
    • 0

割り算と掛け算の順序を逆転させるという、


数式解析のむずかしい技を使ってまで
int型にこだわる理由が全くわかりません。

もしよかったら、その理由を教えていただけますか?

この回答への補足

自分も正直そう思います。
しかし、講師の方がこういう課題を出してきました。結構、天邪鬼なかたなので。
ヒントでは左辺に'÷'右辺に'×'がきたら掛け算を行うということらしいですが、貼り付けてあるソースは
計算された値を一度配列に格納してから、最後に加算しているので難しいと思います。
すみませんが、お力添えをお願いします。

補足日時:2011/07/22 06:54
    • good
    • 0

固定小数という考え方があります。


32bitのint型なら、左側16bitが整数部、右側16bitが小数部として扱う。
この方法ですと整数型で計算することが可能ですが、ただし有効桁数が
浮動小数のfloat、doubleに比べ小さいことに留意しましょう。。

固定小数点演算
http://www2.muroran-it.ac.jp/circle/mpc/front/ol …

参考URL:http://www2.muroran-it.ac.jp/circle/mpc/front/ol …
    • good
    • 0

計算をする前に因数の順番を入れ換えれば良いと思います。


かけ算わり算で繋がっているところを見つけ、
その部分を、かけ算がわり算よりも左側に来るように並べかえるんです。
この前処理さえしてしまえば、
計算処理をするコードを書き換える必要はなくなります。

ただこの方法でも、1 / 2 + 1 / 2のような式には対応できません。
こういった式も処理したいなら、int型整数を2つ使って分数を表現し、
分数を使って計算処理をするという方法が考えられます。
    • good
    • 0

無理です。



int型では常に少数部のカットが行われるのでどうしようもありません。言語仕様ですから、どうしても「10/4*4」の計算で常に「10」と正しい答えを出したいのならフロート型かダブル型を使用して最終的に少数部切ってください。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


このQ&Aを見た人がよく見るQ&A