回答編集履歴

3

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

2020/03/16 00:49

投稿

kazuma-s
kazuma-s

スコア8224

test CHANGED
@@ -283,3 +283,161 @@
283
283
  ラムダ式なんか使っていません。
284
284
 
285
285
  理解できなくてもかまいませんが、どこが分からないかを教えていただけませんか?
286
+
287
+
288
+
289
+ **追記3**
290
+
291
+ 計算を double で行うようにしてみました。
292
+
293
+ ```Java
294
+
295
+ import java.util.Scanner;
296
+
297
+ import java.util.regex.*;
298
+
299
+
300
+
301
+ class Expr {
302
+
303
+ String str; int len, pos; double val;
304
+
305
+ char c, op[] = { '+', '-', '*', '/', '^', '^' };
306
+
307
+ Pattern p = Pattern.compile("\d+\.?\d*([eE][+-]?\d+)?");
308
+
309
+
310
+
311
+ Expr(String s) { str = s; len = s.length(); pos = 0; }
312
+
313
+
314
+
315
+ char get() {
316
+
317
+ while (pos < len)
318
+
319
+ if ((c = str.charAt(pos++)) != ' ' ) {
320
+
321
+ if (!Character.isDigit(c)) return c;
322
+
323
+ String s = str.substring(--pos);
324
+
325
+ Matcher m = p.matcher(s);
326
+
327
+ m.find();
328
+
329
+ s = m.group();
330
+
331
+ val = Double.parseDouble(s);
332
+
333
+ pos += s.length();
334
+
335
+ return c = '0';
336
+
337
+ }
338
+
339
+ return c = 0;
340
+
341
+ }
342
+
343
+
344
+
345
+ double expr(int i) {
346
+
347
+ double v;
348
+
349
+ if (i < 6)
350
+
351
+ for (v = expr(i+2); c == op[i] || c == op[i+1]; )
352
+
353
+ if (c == '+') v += expr(i+2);
354
+
355
+ else if (c == '-') v -= expr(i+2);
356
+
357
+ else if (c == '*') v *= expr(i+2);
358
+
359
+ else if (c == '/') v /= expr(i+2);
360
+
361
+ else v = Math.pow(v, expr(i));
362
+
363
+ else if (get() == '0') { v = val; get(); }
364
+
365
+ else if (c == '(') { v = expr(0); if (c == ')') get(); else c = 2; }
366
+
367
+ else if (c == '+') v = expr(i);
368
+
369
+ else if (c == '-') v = -expr(i);
370
+
371
+ else if (str.startsWith("sqrt(", pos-1)) { pos += 3; v = Math.sqrt(expr(i)); }
372
+
373
+ else v = c = 1;
374
+
375
+ return v;
376
+
377
+ }
378
+
379
+
380
+
381
+ public static void main(String[] args) {
382
+
383
+ for (Scanner scn = new Scanner(System.in); ; ) {
384
+
385
+ System.out.print(">> ");
386
+
387
+ if (!scn.hasNextLine()) break;
388
+
389
+ String s = scn.nextLine();
390
+
391
+ if (s.equals(".")) break;
392
+
393
+ Expr e = new Expr(s);
394
+
395
+ double v = e.expr(0);
396
+
397
+ System.out.println(e.c == 0 ? " " + v : " Error");
398
+
399
+ }
400
+
401
+ }
402
+
403
+ }
404
+
405
+ ```
406
+
407
+ べき乗演算子 ^ や関数 sqrt を追加しています。
408
+
409
+
410
+
411
+ 実行例
412
+
413
+ ```
414
+
415
+ >> 1+2*(3-4)/5
416
+
417
+ 0.6
418
+
419
+ >> 355/113
420
+
421
+ 3.1415929203539825
422
+
423
+ >> sqrt(2)
424
+
425
+ 1.4142135623730951
426
+
427
+ >> (1 + sqrt(5)) / 2
428
+
429
+ 1.618033988749895
430
+
431
+ >> sqrt(3^2 + 4^2)
432
+
433
+ 5.0
434
+
435
+ >> 2^3^2
436
+
437
+ 512.0
438
+
439
+ >> .
440
+
441
+ ```
442
+
443
+ ^ は右結合なので 2^(3^2) となります。

2

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

2020/03/16 00:49

投稿

kazuma-s
kazuma-s

スコア8224

test CHANGED
@@ -119,3 +119,167 @@
119
119
  **追記**
120
120
 
121
121
  get の中の return '0'; を return c = '0'; に修正しました。
122
+
123
+
124
+
125
+ **追記2**
126
+
127
+ 逆ポーランド記法に変換してからそれを評価するようにしてみました。
128
+
129
+ ```Java
130
+
131
+ import java.util.*;
132
+
133
+
134
+
135
+ class Rpn {
136
+
137
+ char c; int pos = 0, len, val; String str, o = "+-*/";
138
+
139
+ StringBuilder sb = new StringBuilder();
140
+
141
+
142
+
143
+ Rpn(String s) { str = s; len = s.length(); }
144
+
145
+
146
+
147
+ char get() {
148
+
149
+ while (pos < len) {
150
+
151
+ c = str.charAt(pos++);
152
+
153
+ if (c != ' ' ) {
154
+
155
+ if (!Character.isDigit(c)) return c;
156
+
157
+ for (val = c - '0'; ; ) {
158
+
159
+ if (pos == len) return c = '0';
160
+
161
+ c = str.charAt(pos++);
162
+
163
+ if (!Character.isDigit(c)) { pos--; return c = '0'; }
164
+
165
+ val = val * 10 + (c - '0');
166
+
167
+ }
168
+
169
+ }
170
+
171
+ }
172
+
173
+ return c = 0;
174
+
175
+ }
176
+
177
+
178
+
179
+ void put(Object o) { sb.append(' ').append(o); }
180
+
181
+
182
+
183
+ void expr(int i) {
184
+
185
+ if (i < 4)
186
+
187
+ for (expr(i + 2); c == o.charAt(i) || c == o.charAt(i + 1); ) {
188
+
189
+ char d = c; expr(i + 2); put(d);
190
+
191
+ }
192
+
193
+ else if (get() == '0') { put(val); get(); }
194
+
195
+ else if (c == '(') { expr(0); if (c == ')') get(); else c = 2; }
196
+
197
+ else if (c == '+') expr(i);
198
+
199
+ else if (c == '-') { expr(i); put('_'); }
200
+
201
+ else c = 1;
202
+
203
+ }
204
+
205
+
206
+
207
+ int eval(String rpn) {
208
+
209
+ Scanner scn = new Scanner(rpn);
210
+
211
+ Stack<Integer> s = new Stack<>();
212
+
213
+ int v;
214
+
215
+ for (;;)
216
+
217
+ if (scn.hasNextInt())
218
+
219
+ s.push(scn.nextInt());
220
+
221
+ else if (scn.hasNext()) {
222
+
223
+ String op = scn.next();
224
+
225
+ if (op.equals("+")) s.push(s.pop() + s.pop());
226
+
227
+ else if (op.equals("-")) s.push(-s.pop() + s.pop());
228
+
229
+ else if (op.equals("*")) s.push(s.pop() * s.pop());
230
+
231
+ else if (op.equals("/")) { v = s.pop(); s.push(s.pop() / v); }
232
+
233
+ else if (op.equals("_")) s.push(-s.pop());
234
+
235
+ else return 0;
236
+
237
+ }
238
+
239
+ else return s.pop();
240
+
241
+ }
242
+
243
+
244
+
245
+ public static void main(String[] args) throws Exception {
246
+
247
+ Scanner scn = new Scanner(System.in);
248
+
249
+ for (;;) {
250
+
251
+ System.out.print(">> ");
252
+
253
+ if (!scn.hasNextLine()) break;
254
+
255
+ String s = scn.nextLine();
256
+
257
+ if (s.equals(".")) break;
258
+
259
+ Rpn rpn = new Rpn(s);
260
+
261
+ rpn.expr(0);
262
+
263
+ if (rpn.c == 0) {
264
+
265
+ s = rpn.sb.toString();
266
+
267
+ System.out.println(s + " ==> " + rpn.eval(s));
268
+
269
+ }
270
+
271
+ else System.out.println(" Error");
272
+
273
+ }
274
+
275
+ }
276
+
277
+ }
278
+
279
+ ```
280
+
281
+ new しているクラスは Scanner, Stack, StringBuilder だけです。
282
+
283
+ ラムダ式なんか使っていません。
284
+
285
+ 理解できなくてもかまいませんが、どこが分からないかを教えていただけませんか?

1

コードの修正

2020/03/14 04:45

投稿

kazuma-s
kazuma-s

スコア8224

test CHANGED
@@ -26,11 +26,11 @@
26
26
 
27
27
  for (val = c - '0'; ; ) {
28
28
 
29
- if (pos == str.length()) return '0';
29
+ if (pos == str.length()) return c ='0';
30
30
 
31
31
  c = str.charAt(pos++);
32
32
 
33
- if (!Character.isDigit(c)) { pos--; return '0'; }
33
+ if (!Character.isDigit(c)) { pos--; return c = '0'; }
34
34
 
35
35
  val = val * 10 + (c - '0');
36
36
 
@@ -113,3 +113,9 @@
113
113
  ```
114
114
 
115
115
  バグのご指摘歓迎します。
116
+
117
+
118
+
119
+ **追記**
120
+
121
+ get の中の return '0'; を return c = '0'; に修正しました。