プロが教える店舗&オフィスのセキュリティ対策術

こんばんわ。

私はC/C++プログラミングの勉強をしていて、下記の会津大学のonline judgeを利用させて頂いています。

http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/ …

この問題を解いているのですが、以下のプログラムを提出するとWrong Answerとなってしまいます。
何度も試行錯誤したのですが、恥ずかしながらWrongAnswerとなってしまう理由がどうしてもわかりません。
どなたかこのプログラムの誤りを指摘して頂けないでしょうか?
よろしくお願い致します。

開発言語はC++です。

--------------------------ここから--------------------------
#include <iostream>

using namespace std;

int main(){
int i,j=0;
int sales_sum=0,amount_sum=0;
double ave;
int cost[1000],amount[1000];

//データを読み込む
while(scanf("%d,%d",&cost[j],&amount[j]) != EOF){
j++;
}

//合計金額と合計数量を計算する
for(i=0;i<j;i++){
sales_sum += cost[i] * amount[i];
amount_sum += amount[i];
}

//数量の平均を計算する
ave = (double)amount_sum / (double)j;

//出力
printf("%d\n%.0lf\n",sales_sum,ave);

return 0;
}
--------------------------ここまで--------------------------

A 回答 (6件)

>%.0lfとすることで小数点以下第1位を四捨五入して出力されるので大丈夫かと思っていたのですが、


> 何か考え方が間違っているのでしょうか。

多分、C の規格上は小数点以下を「丸める」としか定めておらず、
必ずしも四捨五入した結果が得られるとは言い切れないと思います。

自前でコードを書いた方が処理の意図が明確になって良いと思いますよ。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。

そうだったんですか。
今後気をつけようと思います。

お礼日時:2009/03/26 03:36

問題点10


>int cost[1000],amount[1000];

問題文には「入力件数の上限」は特に設けられていないのに、勝手に「1000件まで」という上限が付けられてしまっている。

で、すべての問題点を改良したのが、以下のソース。

#include <stdio.h>

int main(){
int i,count;
int sales_sum,amount_sum,ave;
int cost,amount;

//データを読み込む
for(count = 0,sales_sum = 0,amount_sum = 0;scanf("%d,%d",&cost,&amount) == 2;count++) {
sales_sum += cost * amount;
amount_sum += amount;
}


if (count) {
//数量の平均を計算する
ave = (amount_sum * 10 / count + 5) / 10;

//出力
printf("%d\n%d\n",sales_sum,ave);
}

return 0;
}

一応、これでAcceptedは取得出来ます。
    • good
    • 0

問題点9


>ave = (double)amount_sum / (double)j;

1件も読み込まずに入力がEOFになると、jが0のままになり、0除算例外が発生する。

気付いてない問題点、まだまだありそう…。
    • good
    • 0

問題点8


>while(scanf("%d,%d",&cost[j],&amount[j]) != EOF){
j++;
}

入力が1001行以上あった場合、確保した配列を超えて読み込みが行われ、メモリを破壊する。
    • good
    • 0

問題点1


>int cost[1000],amount[1000];
>while(scanf("%d,%d",&cost[j],&amount[j]) != EOF){
>j++;
>}

このwhileループは「入力が不正」だと終了しなくなる。

例えば、入力が
10,20
100,abc
であった場合、永久にscanfを繰り返す。

問題点2
>double ave;
>printf("%d\n%.0lf\n",sales_sum,ave);

出力の「販売数量の平均」が「整数」ではない。

問題文では「整数であること」が要求されている。

問題点3
>ave = (double)amount_sum / (double)j;

「販売数量の平均」が小数点以下第1位で四捨五入されていない。

問題点4
>#include <iostream>

不要なヘッダーファイルをインクルードしている。

問題点5
>using namespace std;

不要なusing文がある。

問題点6
>while(scanf("%d,%d",&cost[j],&amount[j]) != EOF){
j++;
>printf("%d\n%.0lf\n",sales_sum,ave);

scanf関数やprintf関数が使われているが、それらが宣言されていない。または、それらを宣言しているヘッダーファイル(stdio.h)をインクルードしていない。

問題点7
>何度も試行錯誤したのですが、恥ずかしながらWrongAnswerとなってしまう理由がどうしてもわかりません。

試行錯誤が足りない。
    • good
    • 0
この回答へのお礼

多くのご指摘ありがとうございます。

1.上記サイトの問題では多くの問題において不正な入力がされないため、このようなプログラムになってしまいました。実践では不正値に対処したいと思います。

2.出力時にdouble型の小数点以下を削って(四捨五入して)、整数値に見せかけて出力する方法ではAcceptedされないんですね。実際に整数型として出力すべきでしたね。

3.これも上と同様の理由です。出力時に四捨五入すれば良いと勘違いしていました。

4.完全に私の勘違いです。<stdio.h>をincludeすべきでした。申し訳ありません。

5.私の環境では、この一文がないとscanf,printfが使用できなくなってしまいます。そのため、iostreamをincludeした場合にでもscanf,printfを使用できるものだと思い込んでいました。素直にstdio.hを使用すれば良かったですね…。

6.了解です。ありがとうございます。

7.こんなにも多くの問題を指摘されるとは思いませんでした。お恥ずかしいです。今後とも努力したいと思います。

8,10.おっしゃる通りです。むしろここでは配列を使わなくても良かったんですね。forループ中でsumを計算していくので、cost[]やamount[]にデータを確保しておく意味がありませんよね。

9.不正値が入力される事はないという思い込みがありました。今後は不正値にも対処するプログラムを書くよう気をつけたいです。

chie65535さんが書かれたプログラムの四捨五入する方法は知りませんでしたね。今後も使う機会があるかと思いますので参考にさせて頂きます。

多くのご指摘ありがとうございます。
これらの問題点に注意しながら、もう一度プログラムを書いてみたいと思います。

お礼日時:2009/03/25 15:47

問題文には



> ※販売数量の平均に端数(小数点以下の数)が生じた場合は小数点以下第1 位を四捨五入してください。

とありますが。

あと、なんで #include <iostream> なんです?
    • good
    • 0
この回答へのお礼

double型の平均値aveをprintfで出力する際に、
%.0lfとすることで小数点以下第1位を四捨五入して出力されるので大丈夫かと思っていたのですが、何か考え方が間違っているのでしょうか。

iostreamをincludeした場合でもコンパイルが通り、他のプログラムなどがAcceptedされていたので勘違いしていました。
scanf等を使用しているのでstdio.hをincludeすべきでした。

大変参考になりました。ありがとうございます。

お礼日時:2009/03/25 15:18

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