1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.math.complex;
19
20 import java.io.Serializable;
21 import java.text.FieldPosition;
22 import java.text.Format;
23 import java.text.NumberFormat;
24 import java.text.ParseException;
25 import java.text.ParsePosition;
26 import java.util.Locale;
27
28
29
30
31
32
33
34
35
36 public class ComplexFormat extends Format implements Serializable {
37
38
39 private static final long serialVersionUID = -6337346779577272306L;
40
41
42 private static final String DEFAULT_IMAGINARY_CHARACTER = "i";
43
44
45 private String imaginaryCharacter;
46
47
48 private NumberFormat imaginaryFormat;
49
50
51 private NumberFormat realFormat;
52
53
54
55
56
57 public ComplexFormat() {
58 this(DEFAULT_IMAGINARY_CHARACTER, getDefaultNumberFormat());
59 }
60
61
62
63
64
65
66 public ComplexFormat(NumberFormat format) {
67 this(DEFAULT_IMAGINARY_CHARACTER, format);
68 }
69
70
71
72
73
74
75
76 public ComplexFormat(NumberFormat realFormat,
77 NumberFormat imaginaryFormat) {
78 this(DEFAULT_IMAGINARY_CHARACTER, realFormat, imaginaryFormat);
79 }
80
81
82
83
84
85
86 public ComplexFormat(String imaginaryCharacter) {
87 this(imaginaryCharacter, getDefaultNumberFormat());
88 }
89
90
91
92
93
94
95
96 public ComplexFormat(String imaginaryCharacter, NumberFormat format) {
97 this(imaginaryCharacter, format, (NumberFormat)format.clone());
98 }
99
100
101
102
103
104
105
106
107
108 public ComplexFormat(String imaginaryCharacter, NumberFormat realFormat,
109 NumberFormat imaginaryFormat) {
110 super();
111 setImaginaryCharacter(imaginaryCharacter);
112 setImaginaryFormat(imaginaryFormat);
113 setRealFormat(realFormat);
114 }
115
116
117
118
119
120
121
122
123 public static String formatComplex( Complex c ) {
124 return getInstance().format( c );
125 }
126
127
128
129
130
131
132
133
134
135
136 public StringBuffer format(Complex complex, StringBuffer toAppendTo,
137 FieldPosition pos) {
138
139 pos.setBeginIndex(0);
140 pos.setEndIndex(0);
141
142
143 double re = complex.getReal();
144 formatDouble(re, getRealFormat(), toAppendTo, pos);
145
146
147 double im = complex.getImaginary();
148 if (im < 0.0) {
149 toAppendTo.append(" - ");
150 formatDouble(-im, getImaginaryFormat(), toAppendTo, pos);
151 toAppendTo.append(getImaginaryCharacter());
152 } else if (im > 0.0 || Double.isNaN(im)) {
153 toAppendTo.append(" + ");
154 formatDouble(im, getImaginaryFormat(), toAppendTo, pos);
155 toAppendTo.append(getImaginaryCharacter());
156 }
157
158 return toAppendTo;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public StringBuffer format(Object obj, StringBuffer toAppendTo,
175 FieldPosition pos) {
176
177 StringBuffer ret = null;
178
179 if (obj instanceof Complex) {
180 ret = format( (Complex)obj, toAppendTo, pos);
181 } else if (obj instanceof Number) {
182 ret = format( new Complex(((Number)obj).doubleValue(), 0.0),
183 toAppendTo, pos);
184 } else {
185 throw new IllegalArgumentException(
186 "Cannot format given Object as a Date");
187 }
188
189 return ret;
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 private StringBuffer formatDouble(double value, NumberFormat format,
210 StringBuffer toAppendTo, FieldPosition pos) {
211 if( Double.isNaN(value) || Double.isInfinite(value) ) {
212 toAppendTo.append('(');
213 toAppendTo.append(value);
214 toAppendTo.append(')');
215 } else {
216 format.format(value, toAppendTo, pos);
217 }
218 return toAppendTo;
219 }
220
221
222
223
224
225
226 public static Locale[] getAvailableLocales() {
227 return NumberFormat.getAvailableLocales();
228 }
229
230
231
232
233
234
235
236 private static NumberFormat getDefaultNumberFormat() {
237 return getDefaultNumberFormat(Locale.getDefault());
238 }
239
240
241
242
243
244
245
246
247 private static NumberFormat getDefaultNumberFormat(Locale locale) {
248 NumberFormat nf = NumberFormat.getInstance(locale);
249 nf.setMaximumFractionDigits(2);
250 return nf;
251 }
252
253
254
255
256
257 public String getImaginaryCharacter() {
258 return imaginaryCharacter;
259 }
260
261
262
263
264
265 public NumberFormat getImaginaryFormat() {
266 return imaginaryFormat;
267 }
268
269
270
271
272
273 public static ComplexFormat getInstance() {
274 return getInstance(Locale.getDefault());
275 }
276
277
278
279
280
281
282 public static ComplexFormat getInstance(Locale locale) {
283 NumberFormat f = getDefaultNumberFormat(locale);
284 return new ComplexFormat(f);
285 }
286
287
288
289
290
291 public NumberFormat getRealFormat() {
292 return realFormat;
293 }
294
295
296
297
298
299
300
301
302
303 public Complex parse(String source) throws ParseException {
304 ParsePosition parsePosition = new ParsePosition(0);
305 Complex result = parse(source, parsePosition);
306 if (parsePosition.getIndex() == 0) {
307 throw new ParseException("Unparseable complex number: \"" + source +
308 "\"", parsePosition.getErrorIndex());
309 }
310 return result;
311 }
312
313
314
315
316
317
318
319
320 public Complex parse(String source, ParsePosition pos) {
321 int initialIndex = pos.getIndex();
322
323
324 parseAndIgnoreWhitespace(source, pos);
325
326
327 Number re = parseNumber(source, getRealFormat(), pos);
328 if (re == null) {
329
330
331
332 pos.setIndex(initialIndex);
333 return null;
334 }
335
336
337 int startIndex = pos.getIndex();
338 char c = parseNextCharacter(source, pos);
339 int sign = 0;
340 switch (c) {
341 case 0 :
342
343
344 return new Complex(re.doubleValue(), 0.0);
345 case '-' :
346 sign = -1;
347 break;
348 case '+' :
349 sign = 1;
350 break;
351 default :
352
353
354
355 pos.setIndex(initialIndex);
356 pos.setErrorIndex(startIndex);
357 return null;
358 }
359
360
361 parseAndIgnoreWhitespace(source, pos);
362
363
364 Number im = parseNumber(source, getRealFormat(), pos);
365 if (im == null) {
366
367
368
369 pos.setIndex(initialIndex);
370 return null;
371 }
372
373
374 int n = getImaginaryCharacter().length();
375 startIndex = pos.getIndex();
376 int endIndex = startIndex + n;
377 if (source.substring(startIndex, endIndex).compareTo(
378 getImaginaryCharacter()) != 0) {
379
380
381 pos.setIndex(initialIndex);
382 pos.setErrorIndex(startIndex);
383 return null;
384 }
385 pos.setIndex(endIndex);
386
387 return new Complex(re.doubleValue(), im.doubleValue() * sign);
388 }
389
390
391
392
393
394
395
396
397 private void parseAndIgnoreWhitespace(String source, ParsePosition pos) {
398 parseNextCharacter(source, pos);
399 pos.setIndex(pos.getIndex() - 1);
400 }
401
402
403
404
405
406
407
408
409 private char parseNextCharacter(String source, ParsePosition pos) {
410 int index = pos.getIndex();
411 int n = source.length();
412 char ret = 0;
413
414 if (index < n) {
415 char c;
416 do {
417 c = source.charAt(index++);
418 } while (Character.isWhitespace(c) && index < n);
419 pos.setIndex(index);
420
421 if (index < n) {
422 ret = c;
423 }
424 }
425
426 return ret;
427 }
428
429
430
431
432
433
434
435
436
437
438 private Number parseNumber(String source, double value, ParsePosition pos) {
439 Number ret = null;
440
441 StringBuffer sb = new StringBuffer();
442 sb.append('(');
443 sb.append(value);
444 sb.append(')');
445
446 int n = sb.length();
447 int startIndex = pos.getIndex();
448 int endIndex = startIndex + n;
449 if (endIndex < source.length()) {
450 if (source.substring(startIndex, endIndex).compareTo(sb.toString()) == 0) {
451 ret = new Double(value);
452 pos.setIndex(endIndex);
453 }
454 }
455
456 return ret;
457 }
458
459
460
461
462
463
464
465
466
467
468
469 private Number parseNumber(String source, NumberFormat format, ParsePosition pos) {
470 int startIndex = pos.getIndex();
471 Number number = format.parse(source, pos);
472 int endIndex = pos.getIndex();
473
474
475 if (startIndex == endIndex) {
476
477 double[] special = {Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};
478 for (int i = 0; i < special.length; ++i) {
479 number = parseNumber(source, special[i], pos);
480 if (number != null) {
481 break;
482 }
483 }
484 }
485
486 return number;
487 }
488
489
490
491
492
493
494
495
496
497 public Object parseObject(String source, ParsePosition pos) {
498 return parse(source, pos);
499 }
500
501
502
503
504
505
506 public void setImaginaryCharacter(String imaginaryCharacter) {
507 if (imaginaryCharacter == null || imaginaryCharacter.length() == 0) {
508 throw new IllegalArgumentException(
509 "imaginaryCharacter must be a non-empty string.");
510 }
511 this.imaginaryCharacter = imaginaryCharacter;
512 }
513
514
515
516
517
518
519
520 public void setImaginaryFormat(NumberFormat imaginaryFormat) {
521 if (imaginaryFormat == null) {
522 throw new IllegalArgumentException(
523 "imaginaryFormat can not be null.");
524 }
525 this.imaginaryFormat = imaginaryFormat;
526 }
527
528
529
530
531
532
533
534 public void setRealFormat(NumberFormat realFormat) {
535 if (realFormat == null) {
536 throw new IllegalArgumentException(
537 "realFormat can not be null.");
538 }
539 this.realFormat = realFormat;
540 }
541 }