質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

1775閲覧

計算問題を表示させるツール作成における÷0に対する対処がうまくいきません。

mami99

総合スコア6

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2019/08/25 04:39

編集2019/08/25 04:41

前提・実現したいこと

計算問題が生成されるプログラムを作成しています。
条件は以下の通りです。

・計算式は全てで5問表示される。
・1問、4つの数字をランダム、3つの演算子をランダムに表示させる。
・5問の中で4つすべての算術演算子が使われるようにする。
・1つの計算式に使われる算術演算子は最低2つ。

しかし、÷0の問題が出力されると問題が発生します。

初心者の書くコードなんて読み辛いことこの上ないでしょうが、
以下のことを教えていただけると嬉しいです。

・問題点に対する具体的な対処方法。
・(もしよろしければ)その他コードの添削。

発生している問題

÷0の問題が出力された際、その問題が表示され、回答が入力できてしまう。

該当のソースコード

java

1public class Main { 2 public static void main(String[] args) { 3 4 Calculation.setOperator(); 5 6 } 7}

java

1import java.util.ArrayList; 2import java.util.InputMismatchException; 3import java.util.List; 4import java.util.Random; 5import java.util.Scanner; 6 7public class Calculation { 8 9 //演算子を決めるメソッド 10 public static void setOperator() { 11 12 Random rm = new Random(); 13 String[] operators = { "+", "-", "×", "÷" }; 14 15 //フラグ判定 16 boolean[] used = new boolean[4]; 17 18 //3つの演算子を5セット格納 19 String operator[][] = new String[5][3]; 20 21 while (true) { 22 23 for (int i = 0; i < 4; i++) { 24 used[i] = false; 25 } 26 27 for (int i = 0; i < 5; i++) { 28 29 //1つの式に最低2つ以上の演算子が使われているかを確認 30 while (true) { 31 int o = rm.nextInt(4); 32 operator[i][0] = operators[o]; 33 used[o] = true; 34 35 o = rm.nextInt(4); 36 operator[i][1] = operators[o]; 37 used[o] = true; 38 39 o = rm.nextInt(4); 40 operator[i][2] = operators[o]; 41 used[o] = true; 42 if (!operator[i][0].equals(operator[i][1]) && !operator[i][0].equals(operator[i][2])) { 43 break; 44 } 45 } 46 } 47 48 //5つの式で4つの演算子が使われているかを確認 49 boolean ok = true; 50 for (int i = 0; i < 4; i++) { 51 if (used[i] == false) 52 ok = false; 53 } 54 if (ok) { 55 break; 56 57 } 58 } 59 60 for (int i = 0; i < 5; i++) { 61 calculate(operator[i][0], operator[i][1], operator[i][2], i); 62 } 63 64 } 65 66 //四則演算メソッド 67 public static void calculate(String operator1, String operator2, String operator3, int count) { 68 69 Random rm = new Random(); 70 71 List<String> list = new ArrayList<>(); 72 73 boolean aaa = true; 74 75 //計算式を表示するためのリスト 76 List<String> formulaList = new ArrayList<>(); 77 78 String operator = null; 79 80 int value = rm.nextInt(5); 81 int beforeValue = value; 82 formulaList.add(String.valueOf(beforeValue)); 83 84 for (int i = 0; i < 3; i++) { 85 switch (i) { 86 case 0: 87 operator = operator1; 88 formulaList.add(operator1); 89 break; 90 91 case 1: 92 operator = operator2; 93 formulaList.add(operator2); 94 break; 95 96 case 2: 97 operator = operator3; 98 formulaList.add(operator3); 99 break; 100 101 } 102 103 value = rm.nextInt(5); 104 formulaList.add(String.valueOf(value)); 105 106 //×,÷を先に計算、+,-はリストに格納 107 switch (operator) { 108 case "+": 109 list.add(beforeValue + ""); 110 list.add("+"); 111 beforeValue = value; 112 break; 113 114 case "-": 115 list.add(beforeValue + ""); 116 list.add("-"); 117 beforeValue = value; 118 break; 119 120 case "×": 121 beforeValue *= value; 122 break; 123 124 case "÷": 125 try { 126 beforeValue /= value; 127 } catch (ArithmeticException e) { 128 129 System.out.println("※÷0はだめです。"); 130 System.out.println("========================="); 131 132 } 133 break; 134 } 135 } 136 137 list.add(beforeValue + ""); 138 int correctAnswer = Integer.parseInt(list.get(0)); 139 140 //リストに+,-があれば計算 141 for (int i = 0; i < list.size(); i++) { 142 String s = list.get(i); 143 if (s.equals("+")) { 144 correctAnswer += Integer.parseInt(list.get(i + 1)); 145 } else if (s.equals("-")) { 146 correctAnswer -= Integer.parseInt(list.get(i + 1)); 147 } 148 } 149 150 question(formulaList, count, correctAnswer); 151 152 } 153 154 //問題表示メソッド 155 static void question(List<String> formulaList, int count, int correctAnswer) { 156 157 int correctInput; 158 159 // 「1」を返されると同じ問題を繰り返す 160 do { 161 System.out.print("問題" + (count + 1) + ")"); 162 163 for (int i = 0; i < formulaList.size(); i++) { 164 System.out.print(formulaList.get(i)); 165 } 166 167 System.out.println("="); 168 correctInput = decide(correctAnswer); 169 170 } while (correctInput == 1); 171 172 } 173 174 //正誤判定メソッド 175 static int decide(int correctAnswer) { 176 177 int yourAnswer = 0; 178 Scanner scanner = new Scanner(System.in); 179 180 //数字以外を入力すると「1」を返す 181 try { 182 yourAnswer = scanner.nextInt(); 183 } catch (InputMismatchException e) { 184 System.out.println("※整数を入力してください。"); 185 return 1; 186 } 187 188 if (yourAnswer == correctAnswer) { 189 System.out.println("【正解】"); 190 191 } else { 192 System.out.println("【不正解】"); 193 194 } 195 System.out.println("========================="); 196 return 0; 197 198 } 199 200} 201 202

試したこと

÷0をキャッチした回数分、問題を再生成させるようにするために以下のコードを書いた。
ただ、問題の表示がおかしくなる。

試したソースコード

java

1public class Main { 2 public static void main(String[] args) { 3 4 Calculation.setOperator(0); 5 6 } 7} 8

Java

1import java.util.ArrayList; 2import java.util.InputMismatchException; 3import java.util.List; 4import java.util.Random; 5import java.util.Scanner; 6 7public class Calculation { 8 9 //演算子を決めるメソッド 10 public static void setOperator(int count) { 11 12 Random rm = new Random(); 13 String[] operators = { "+", "-", "×", "÷" }; 14 15 //フラグ判定 16 boolean[] used = new boolean[4]; 17 18 //3つの演算子を5セット格納 19 String operator[][] = new String[5][3]; 20 21 while (true) { 22 23 for (int i = 0; i < 4; i++) { 24 used[i] = false; 25 } 26 27 for (int i = 0; i < 5; i++) { 28 29 //1つの式に最低2つ以上の演算子が使われているかを確認 30 while (true) { 31 int o = rm.nextInt(4); 32 operator[i][0] = operators[o]; 33 used[o] = true; 34 35 o = rm.nextInt(4); 36 operator[i][1] = operators[o]; 37 used[o] = true; 38 39 o = rm.nextInt(4); 40 operator[i][2] = operators[o]; 41 used[o] = true; 42 if (!operator[i][0].equals(operator[i][1]) && !operator[i][0].equals(operator[i][2])) { 43 break; 44 } 45 } 46 } 47 48 //5つの式で4つの演算子が使われているかを確認 49 boolean ok = true; 50 for (int i = 0; i < 4; i++) { 51 if (used[i] == false) 52 ok = false; 53 } 54 if (ok) { 55 break; 56 57 } 58 } 59 60 if (count == 0) { 61 for (int i = 0; i < 5; i++) { 62 calculate(operator[i][0], operator[i][1], operator[i][2], i); 63 } 64 } else { 65 66 calculate(operator[count][0], operator[count][1], operator[count][2], count); 67 68 } 69 70 } 71 72 //四則演算メソッド 73 public static void calculate(String operator1, String operator2, String operator3, int count) { 74 75 Random rm = new Random(); 76 77 List<String> list = new ArrayList<>(); 78 79 boolean aaa = true; 80 81 //計算式を表示するためのリスト 82 List<String> formulaList = new ArrayList<>(); 83 84 String operator = null; 85 86 int value = rm.nextInt(5); 87 int beforeValue = value; 88 formulaList.add(String.valueOf(beforeValue)); 89 90 for (int i = 0; i < 3; i++) { 91 switch (i) { 92 case 0: 93 operator = operator1; 94 formulaList.add(operator1); 95 break; 96 97 case 1: 98 operator = operator2; 99 formulaList.add(operator2); 100 break; 101 102 case 2: 103 operator = operator3; 104 formulaList.add(operator3); 105 break; 106 107 } 108 109 value = rm.nextInt(5); 110 formulaList.add(String.valueOf(value)); 111 112 //×,÷を先に計算、+,-はリストに格納 113 switch (operator) { 114 case "+": 115 list.add(beforeValue + ""); 116 list.add("+"); 117 beforeValue = value; 118 break; 119 120 case "-": 121 list.add(beforeValue + ""); 122 list.add("-"); 123 beforeValue = value; 124 break; 125 126 case "×": 127 beforeValue *= value; 128 break; 129 130 case "÷": 131 try { 132 beforeValue /= value; 133 } catch (ArithmeticException e) { 134 135 System.out.println("※÷0はだめです。"); 136 System.out.println("========================="); 137 setOperator(count); 138 139 } 140 break; 141 } 142 } 143 144 list.add(beforeValue + ""); 145 int correctAnswer = Integer.parseInt(list.get(0)); 146 147 //リストに+,-があれば計算 148 for (int i = 0; i < list.size(); i++) { 149 String s = list.get(i); 150 if (s.equals("+")) { 151 correctAnswer += Integer.parseInt(list.get(i + 1)); 152 } else if (s.equals("-")) { 153 correctAnswer -= Integer.parseInt(list.get(i + 1)); 154 } 155 } 156 157 question(formulaList, count, correctAnswer); 158 159 } 160 161 //問題表示メソッド 162 static void question(List<String> formulaList, int count, int correctAnswer) { 163 164 int correctInput; 165 166 // 「1」を返されると同じ問題を繰り返す 167 do { 168 System.out.print("問題" + (count + 1) + ")"); 169 170 for (int i = 0; i < formulaList.size(); i++) { 171 System.out.print(formulaList.get(i)); 172 } 173 174 System.out.println("="); 175 correctInput = decide(correctAnswer); 176 177 } while (correctInput == 1); 178 179 } 180 181 //正誤判定メソッド 182 static int decide(int correctAnswer) { 183 184 int yourAnswer = 0; 185 Scanner scanner = new Scanner(System.in); 186 187 //数字以外を入力すると「1」を返す 188 try { 189 yourAnswer = scanner.nextInt(); 190 } catch (InputMismatchException e) { 191 System.out.println("※整数を入力してください。"); 192 return 1; 193 } 194 195 if (yourAnswer == correctAnswer) { 196 System.out.println("【正解】"); 197 198 } else { 199 System.out.println("【不正解】"); 200 201 } 202 System.out.println("========================="); 203 return 0; 204 205 } 206 207}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

質問への直接の回答としては、「『÷0』が入るかどうかの判定のタイミングと再設定のタイミングがおかしい」です。その原因として、演算子の選択と数字の選択が別メソッドに分かれていることが挙げられます。演算子を全部選んでから数字を選ぶという行動をしているため、巻き戻して演算子から選ぼうとすれば、再度演算子が5回選ばれます。その前に選んだ演算子や数字もそのまま残っている(再帰で呼び出しているだけだからるため、当然表示数が増えることになります。
なので、1つの式を完成させ、それに「÷0」がないかチェックするまでを1つの動作とする必要があります。そこまでするなら、演算子に÷が選ばれた場合は乱数から0をはじく、という動作のほうが簡単だと思います。かっこが使われない限り、÷より先に別の演算がなされ、結果として÷0になる、という可能性はありませんから。

それ以外にもツッコミどころを1つ指摘すると…

  • 次の文は「演算子を2つ以上使っている」の判定として不適切

java

1if (!operator[i][0].equals(operator[i][1]) && !operator[i][0].equals(operator[i][2]))

0番と1番、0番と2番の両方が等しくないときにのみこのifを通るので、
0番と1番が+、2番が-
のようなケースがこのifを通過できません。
「演算子を2つ以上使っている」の否定は「演算子を1つしか使っていない」、つまり「すべて同じ演算子」となるため、正しい判定文の例は次のようになります。

java

1if (!(operator[i][0].equals(operator[i][1]) && operator[i][0].equals(operator[i][2])))

投稿2019/08/25 13:34

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mami99

2019/08/26 11:12

ご回答ありがとうございます。 考え方から改めてみます。 また、条件に関しても教えてくださりありがとうございます。 こういったミスをなくしていきたいですね……。
guest

0

加算、減算、乗算においても、0を対象とすると簡単すぎるので、乱数で生成する数字から0の場合を除外するのが良いと思います。

投稿2019/08/25 06:00

otn

総合スコア84553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mami99

2019/08/25 09:02

ご回答ありがとうございます。 コード以前の問題でしたか。 ちなみに、0が入力されることも想定した場合はどうすればいいですか?
guest

0

・(もしよろしければ)その他コードの添削。

添削になっていませんが, 勢いで書いてみました.
ゼロ割りは例外を生成してキャッチしています.

java

1import java.util.ArrayDeque; 2import java.util.Deque; 3import java.util.InputMismatchException; 4import java.util.Random; 5import java.util.Scanner; 6 7public class Main { 8 static final int Q_COUNT = 5; //問題数 9 static final int E_COUNT = 7; //式の要素数 10 static final int V_MAX = 5; //数値要素の最大値+1 11 12 public static void main(String[] args) { 13 int[][] formulas = createFormulas(); 14 15 Scanner scanner = new Scanner(System.in); 16 for(int i=0; i<Q_COUNT; i++) { 17 while(true) { 18 System.out.print("問題 " + (i+1) + ") "); 19 System.out.println(toFormulaString(formulas[i])+"="); 20 21 try { 22 int yourAnswer = scanner.nextInt(); 23 int correctAnswer = ReversePolishNotation.calculate(formulas[i]); 24 if (yourAnswer == correctAnswer) { 25 System.out.println("【正解】"); 26 } else { 27 System.out.println("【不正解】 正解は"+correctAnswer); 28 } 29 System.out.println("========================="); 30 break; 31 } catch (InputMismatchException e) { 32 System.out.println("※整数を入力してください。"); 33 scanner.next(); //捨てる 34 } 35 } 36 } 37 System.out.println("お疲れ様でした。"); 38 } 39 40 static int[][] createFormulas() { 41 int formulas[][] = new int[Q_COUNT][E_COUNT]; //式数, 偶数番目=数値,奇数番目=演算子 42 Random rm = new Random(); 43 44 //演算子を4種類全て使用したら終了 45 for(int usedBits=0; usedBits!=(1<<Operator.size())-1; ) { 46 usedBits = 0; 47 for(int i=0; i<Q_COUNT; i++) { 48 while(true) { 49 for(int j=0; j<E_COUNT; j++) { 50 formulas[i][j] = rm.nextInt(j%2==0?V_MAX:Operator.size()); 51 } 52 //演算子が全て同じならもう一度生成 53 boolean ok = false; 54 for(int j=3; j<formulas[i].length; j+=2) ok |= formulas[i][1] != formulas[i][j]; 55 if(!ok) continue; 56 57 //計算してみる 58 try { 59 ReversePolishNotation.calculate(formulas[i]); 60 } catch(DivisionByZeroException e) { //ゼロ割り 61 //System.out.println(toFormulaString(formulas[i])+" ... ゼロ割り"); 62 continue; 63 } 64 65 break; 66 } 67 for(int j=1; j<formulas[i].length; j+=2) usedBits |= 1<<formulas[i][j]; 68 } 69 } 70 return formulas; 71 } 72 73 static String toFormulaString(int formula[]) { 74 StringBuilder sb = new StringBuilder(); 75 for(int i=0; i<formula.length; i++) { 76 if(i%2 == 0) sb.append(formula[i]); 77 else sb.append(Operator.valueOf(formula[i]).toString()); 78 } 79 return sb.toString(); 80 } 81 82 //ゼロ割り例外 83 static class DivisionByZeroException extends ArithmeticException { 84 DivisionByZeroException() { super(); }; 85 } 86 87 static enum Operator { 88 ADD(0,"+",(v1,v2)->{ return v1+v2; }), 89 SUB(0,"-",(v1,v2)->{ return v1-v2; }), 90 MUL(1,"*",(v1,v2)->{ return v1*v2; }), 91 DIV(1,"/",(v1,v2)->{ if(v2 == 0) throw new DivisionByZeroException(); return v1/v2; }); 92 93 interface Calculator { 94 int calculate(int value1, int value2); 95 } 96 97 private int priority; //加減乗除の優先順位 98 private String str; //表示用文字列 99 private Calculator calculator; //計算機 100 private Operator(int priority, String str, Calculator calculator) { 101 this.priority = priority; 102 this.str = str; 103 this.calculator = calculator; 104 } 105 public int getPriority() { return priority; } 106 public int calculate(int v1, int v2) { return calculator.calculate(v1,v2); } 107 @Override 108 public String toString() { return str; } 109 110 static Operator valueOf(int operator) { return values()[operator]; } 111 static int size() { return 4; } //(valueOf(int) で指定できる)演算子の数 112 } 113 114 static class ReversePolishNotation { 115 private ReversePolishNotation() {} 116 117 static int calculate(int formula[]) { 118 return calculate(create(formula)); 119 } 120 121 static private class FormulaElement { 122 private int value; 123 private Operator operator; 124 FormulaElement(int value) { 125 this.value = value; 126 this.operator = null; 127 } 128 FormulaElement(Operator operator) { 129 this.value = 0; 130 this.operator = operator; 131 } 132 int getValue() { return value; } 133 Operator getOperator() { return operator; } 134 boolean isOperator() { return operator != null; } 135 136 @Override 137 public String toString() { 138 return isOperator() ? operator.toString() : ""+value; 139 } 140 } 141 142 //変換 143 static private Deque<FormulaElement> create(int formula[]) { 144 Deque<FormulaElement> fQueue = new ArrayDeque<>(); 145 Deque<Operator> oStack = new ArrayDeque<>(); 146 for(int i=0; i<formula.length; i++) { 147 if(i%2 == 0) { //数値 148 fQueue.add(new FormulaElement(formula[i])); 149 } else { //演算子 150 Operator t = Operator.valueOf(formula[i]); 151 while(oStack.size() > 0 && oStack.peek().getPriority() >= t.getPriority()) { 152 fQueue.add(new FormulaElement(oStack.pop())); 153 } 154 oStack.push(t); 155 } 156 } 157 while(oStack.size() > 0) fQueue.add(new FormulaElement(oStack.pop())); 158 return fQueue; 159 } 160 161 //計算 162 static private int calculate(Deque<FormulaElement> fStack) { 163 Deque<Integer> vStack = new ArrayDeque<>(); 164 while(fStack.size() > 0) { 165 FormulaElement e = fStack.pop(); 166 if(e.isOperator()) { 167 int v2 = vStack.pop(); 168 int v1 = vStack.pop(); 169 vStack.push(e.getOperator().calculate(v1,v2)); 170 } else { 171 vStack.push(e.getValue()); 172 } 173 } 174 return vStack.pop(); 175 } 176 } 177}

投稿2019/08/26 08:05

jimbe

総合スコア12646

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mami99

2019/08/26 13:13

ご回答ありがとうございます。 ゆっくり読み解いていこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問