teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

double で計算を行うコードを追加

2020/03/16 00:49

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -140,4 +140,83 @@
140
140
  ```
141
141
  new しているクラスは Scanner, Stack, StringBuilder だけです。
142
142
  ラムダ式なんか使っていません。
143
- 理解できなくてもかまいませんが、どこが分からないかを教えていただけませんか?
143
+ 理解できなくてもかまいませんが、どこが分からないかを教えていただけませんか?
144
+
145
+ **追記3**
146
+ 計算を double で行うようにしてみました。
147
+ ```Java
148
+ import java.util.Scanner;
149
+ import java.util.regex.*;
150
+
151
+ class Expr {
152
+ String str; int len, pos; double val;
153
+ char c, op[] = { '+', '-', '*', '/', '^', '^' };
154
+ Pattern p = Pattern.compile("\d+\.?\d*([eE][+-]?\d+)?");
155
+
156
+ Expr(String s) { str = s; len = s.length(); pos = 0; }
157
+
158
+ char get() {
159
+ while (pos < len)
160
+ if ((c = str.charAt(pos++)) != ' ' ) {
161
+ if (!Character.isDigit(c)) return c;
162
+ String s = str.substring(--pos);
163
+ Matcher m = p.matcher(s);
164
+ m.find();
165
+ s = m.group();
166
+ val = Double.parseDouble(s);
167
+ pos += s.length();
168
+ return c = '0';
169
+ }
170
+ return c = 0;
171
+ }
172
+
173
+ double expr(int i) {
174
+ double v;
175
+ if (i < 6)
176
+ for (v = expr(i+2); c == op[i] || c == op[i+1]; )
177
+ if (c == '+') v += expr(i+2);
178
+ else if (c == '-') v -= expr(i+2);
179
+ else if (c == '*') v *= expr(i+2);
180
+ else if (c == '/') v /= expr(i+2);
181
+ else v = Math.pow(v, expr(i));
182
+ else if (get() == '0') { v = val; get(); }
183
+ else if (c == '(') { v = expr(0); if (c == ')') get(); else c = 2; }
184
+ else if (c == '+') v = expr(i);
185
+ else if (c == '-') v = -expr(i);
186
+ else if (str.startsWith("sqrt(", pos-1)) { pos += 3; v = Math.sqrt(expr(i)); }
187
+ else v = c = 1;
188
+ return v;
189
+ }
190
+
191
+ public static void main(String[] args) {
192
+ for (Scanner scn = new Scanner(System.in); ; ) {
193
+ System.out.print(">> ");
194
+ if (!scn.hasNextLine()) break;
195
+ String s = scn.nextLine();
196
+ if (s.equals(".")) break;
197
+ Expr e = new Expr(s);
198
+ double v = e.expr(0);
199
+ System.out.println(e.c == 0 ? " " + v : " Error");
200
+ }
201
+ }
202
+ }
203
+ ```
204
+ べき乗演算子 ^ や関数 sqrt を追加しています。
205
+
206
+ 実行例
207
+ ```
208
+ >> 1+2*(3-4)/5
209
+ 0.6
210
+ >> 355/113
211
+ 3.1415929203539825
212
+ >> sqrt(2)
213
+ 1.4142135623730951
214
+ >> (1 + sqrt(5)) / 2
215
+ 1.618033988749895
216
+ >> sqrt(3^2 + 4^2)
217
+ 5.0
218
+ >> 2^3^2
219
+ 512.0
220
+ >> .
221
+ ```
222
+ ^ は右結合なので 2^(3^2) となります。

2

逆ポーランド記法に変換するコードを追加

2020/03/16 00:49

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -58,4 +58,86 @@
58
58
  バグのご指摘歓迎します。
59
59
 
60
60
  **追記**
61
- get の中の return '0'; を return c = '0'; に修正しました。
61
+ get の中の return '0'; を return c = '0'; に修正しました。
62
+
63
+ **追記2**
64
+ 逆ポーランド記法に変換してからそれを評価するようにしてみました。
65
+ ```Java
66
+ import java.util.*;
67
+
68
+ class Rpn {
69
+ char c; int pos = 0, len, val; String str, o = "+-*/";
70
+ StringBuilder sb = new StringBuilder();
71
+
72
+ Rpn(String s) { str = s; len = s.length(); }
73
+
74
+ char get() {
75
+ while (pos < len) {
76
+ c = str.charAt(pos++);
77
+ if (c != ' ' ) {
78
+ if (!Character.isDigit(c)) return c;
79
+ for (val = c - '0'; ; ) {
80
+ if (pos == len) return c = '0';
81
+ c = str.charAt(pos++);
82
+ if (!Character.isDigit(c)) { pos--; return c = '0'; }
83
+ val = val * 10 + (c - '0');
84
+ }
85
+ }
86
+ }
87
+ return c = 0;
88
+ }
89
+
90
+ void put(Object o) { sb.append(' ').append(o); }
91
+
92
+ void expr(int i) {
93
+ if (i < 4)
94
+ for (expr(i + 2); c == o.charAt(i) || c == o.charAt(i + 1); ) {
95
+ char d = c; expr(i + 2); put(d);
96
+ }
97
+ else if (get() == '0') { put(val); get(); }
98
+ else if (c == '(') { expr(0); if (c == ')') get(); else c = 2; }
99
+ else if (c == '+') expr(i);
100
+ else if (c == '-') { expr(i); put('_'); }
101
+ else c = 1;
102
+ }
103
+
104
+ int eval(String rpn) {
105
+ Scanner scn = new Scanner(rpn);
106
+ Stack<Integer> s = new Stack<>();
107
+ int v;
108
+ for (;;)
109
+ if (scn.hasNextInt())
110
+ s.push(scn.nextInt());
111
+ else if (scn.hasNext()) {
112
+ String op = scn.next();
113
+ if (op.equals("+")) s.push(s.pop() + s.pop());
114
+ else if (op.equals("-")) s.push(-s.pop() + s.pop());
115
+ else if (op.equals("*")) s.push(s.pop() * s.pop());
116
+ else if (op.equals("/")) { v = s.pop(); s.push(s.pop() / v); }
117
+ else if (op.equals("_")) s.push(-s.pop());
118
+ else return 0;
119
+ }
120
+ else return s.pop();
121
+ }
122
+
123
+ public static void main(String[] args) throws Exception {
124
+ Scanner scn = new Scanner(System.in);
125
+ for (;;) {
126
+ System.out.print(">> ");
127
+ if (!scn.hasNextLine()) break;
128
+ String s = scn.nextLine();
129
+ if (s.equals(".")) break;
130
+ Rpn rpn = new Rpn(s);
131
+ rpn.expr(0);
132
+ if (rpn.c == 0) {
133
+ s = rpn.sb.toString();
134
+ System.out.println(s + " ==> " + rpn.eval(s));
135
+ }
136
+ else System.out.println(" Error");
137
+ }
138
+ }
139
+ }
140
+ ```
141
+ new しているクラスは Scanner, Stack, StringBuilder だけです。
142
+ ラムダ式なんか使っていません。
143
+ 理解できなくてもかまいませんが、どこが分からないかを教えていただけませんか?

1

コードの修正

2020/03/14 04:45

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -12,9 +12,9 @@
12
12
  if ((c = str.charAt(pos++)) != ' ' ) {
13
13
  if (!Character.isDigit(c)) return c;
14
14
  for (val = c - '0'; ; ) {
15
- if (pos == str.length()) return '0';
15
+ if (pos == str.length()) return c ='0';
16
16
  c = str.charAt(pos++);
17
- if (!Character.isDigit(c)) { pos--; return '0'; }
17
+ if (!Character.isDigit(c)) { pos--; return c = '0'; }
18
18
  val = val * 10 + (c - '0');
19
19
  }
20
20
  }
@@ -55,4 +55,7 @@
55
55
  }
56
56
  }
57
57
  ```
58
- バグのご指摘歓迎します。
58
+ バグのご指摘歓迎します。
59
+
60
+ **追記**
61
+ get の中の return '0'; を return c = '0'; に修正しました。