1
2
3 package eu.simuline.util;
4
5 import java.math.BigInteger;
6 import java.math.BigDecimal;
7
8 import java.util.Map;
9 import java.util.HashMap;
10
11 /**
12 * Describes the representation of a real value,
13 * which may be either a double, resp. a Double-value
14 * or a {@link BigDecimal} for use in tables.
15 * At a rudimentary stage, {@link RealRepresentation} wraps the number
16 * whereas {@link RealRepresentation.Desc} describes
17 * how to format it, e.g. where to add blanks.
18 * <p>
19 * Also {@link #asInteger} provides some support for formatting integers.
20 * These are the two supported levels of precision.
21 * It is characterized by the {@link #mantissa} and the {@link #exponent}.
22 * The mantissa in turn
23 * splits into the {@link #integer} and the {@link #fraction}al part.
24 * The essential point is that these three parts are properly aligned
25 * and filled up with <code>0</code>'s and blanks by need.
26 * <p>
27 * The splitting between integer, fraction and exponent is
28 * as specified for {@link Double#toString(double)}.
29 * The difference between the two levels of precision
30 * is made as transparent as possible.
31 * Transparence is given up in (at least) the following cases:
32 * <ul>
33 * <li>
34 * unlike <code>BigDecimal</code>s
35 * <code>double</code>s (influenced by the standard IEEE 754),
36 * distinguish between <code>+0</code> and <code>-0</code>.
37 * <li>
38 * for doubles by specification of the string representation,
39 * <pre>
40 * "There must be at least one digit to represent the fractional part,
41 * and beyond that as many, but only as many,
42 * more digits as are needed to uniquely distinguish the argument value
43 * from adjacent values of type double.
44 * That is, suppose that x is the exact mathematical value
45 * represented by the decimal representation produced by this method
46 * for a finite nonzero argument d.
47 * Then d must be the double value nearest to x;
48 * or if two double values are equally close to x,
49 * then d must be one of them
50 * and the least significant bit of the significand of d must be 0. "
51 * </pre>
52 * This does not make sense for <code>BigDecimals</code>
53 * because there is no nearest <code>BigDecimal</code>:
54 * The <code>BigDecimal</code>s are "almost" dense in the real numbers.
55 * Instead we neglect any trailing zeros.
56 * In later versions, this should be different.
57 * </ul>
58 *
59 * Also infinite <code>double</code>'s and <code>NaN</code> are not supported.
60 * This is because they have no splitting into integer,
61 * fractional part and exponent.
62 * They do not make sense for <code>BigDecimal</code>s
63 * and so this would make transparency more difficult.
64 * Note that denormalization of <code>double</code>'s
65 * does not affect their string representation
66 * such that this is completely as forfor<code>BigDecimal</code>s
67 * for which automatic denormalization does not make sense
68 * (although can be forced by the user).
69 *
70 */
71 public class RealRepresentation {
72
73 /* -------------------------------------------------------------------- *
74 * class constants. *
75 * -------------------------------------------------------------------- */
76
77 /**
78 * Describe the action to be taken if a sequence of symbols,
79 * e.g. digits are longer as needed.
80 *
81 * @see #alignLeft
82 * @see #alignRight
83 */
84 public static final Cutter ALIGN_CUT_OFF_LEFT = new Cutter() {
85 public String cut(String str, int len) {
86 int strLen = str.length();
87 return str.substring(strLen - len, strLen);
88 }
89 };
90
91 /**
92 * Describe the action to be taken if a sequence of symbols,
93 * e.g. digits are longer as needed.
94 *
95 * @see #alignLeft
96 * @see #alignRight
97 */
98 public static final Cutter ALIGN_CUT_OFF_RIGHT = new Cutter() {
99 public String cut(String str, int len) {
100 return str.substring(0, len);
101 }
102 };
103
104 /**
105 * Describe the action to be taken if a sequence of symbols,
106 * e.g. digits are longer as needed.
107 *
108 * @see #alignLeft
109 * @see #alignRight
110 * @see #trimExponent
111 */
112 public static final Cutter ALIGN_EXCEPTION = new Cutter() {
113 public String cut(String str, int len) {
114 throw new IllegalArgumentException
115 ("String \"" + str + "\" longer than expected (" +
116 len + "). ");
117
118 }
119 };
120
121 /**
122 * Describe the action to be taken if a sequence of symbols,
123 * e.g. digits are longer as desired.
124 *
125 * @see #alignLeft
126 * @see #alignRight
127 * @see #trimExponent
128 */
129 public static final Cutter ALIGN_LEAVE_UNCHANGED = new Cutter() {
130 public String cut(String str, int len) {
131 return str;
132 }
133 };
134
135 /**
136 * The keys are Characters (intended for either " " or "0")
137 * and the associated values are strings
138 * consisting of a number of characters given by the key.
139 *
140 * @see #fill
141 */
142 private static final Map<Character, String> FILL_STRINGS =
143 new HashMap<Character, String>();
144
145 /**
146 * A string containing the character signifying an exponent.
147 * This is <code>e</code> but could also be <code>E</code>.
148 */
149 public static final String EXP_CHAR = "e";
150
151 /**
152 * Substitutes the place for the point
153 * in case the real number represented has no fractional part.
154 * This is either " " or "".
155 * The default value is " ".
156 *
157 * @see #compensatePoint
158 */
159 private static String noPointS = " ";
160
161 /**
162 * A string constant containing the decimal point.
163 */
164 private static final String POINT_S = ".";
165
166 /**
167 * A character constant containing <code>+</code>.
168 */
169 private static final String SIGN_PLUS = "+";
170
171 /**
172 * A character constant containing <code>+</code>.
173 */
174 private static final String SIGN_MINUS = "-";
175
176 /**
177 * Sets {@link #noPointS} according to the parameter:
178 * <code>true</code> means that {@link #noPointS} is attached with " ";
179 * otherwise it is "".
180 *
181 * @param compensate
182 * a <code>boolean</code> deciding
183 * whether to compensate a decimal point
184 * in case the real number represented has no fractional part.
185 */
186 public static void compensatePoint(boolean compensate) {
187 noPointS = compensate ? " " : "";
188 }
189
190 /* -------------------------------------------------------------------- *
191 * inner classes. *
192 * -------------------------------------------------------------------- */
193
194 /**
195 * Describes the representation of a {@link BigDecimal}-value.
196 * It is characterized
197 * by the {@link #mantissa} and the {@link #exponent}.
198 * The mantissa in turn
199 * splits into the {@link #integer} and the {@link #fraction}al part.
200 *
201 * @author <a href="mailto:e.reissner@rose.de">Ernst Reissner</a>
202 * @version 1.0
203 */
204 private static final class BigDecimalRep extends RealRepresentation {
205
206 /**
207 * The number of digits right of the point
208 * such that the representation is without exponent.
209 * This evaluates to <code>-3</code> as specified for double's
210 * in {@link Double#toString(double)} and is used by
211 * {@link #BigDecimalRep(BigDecimal)}.
212 */
213 private static final int MAX_FRAC_DIGITS_NO_EXP = -3;
214
215 /**
216 * The number of digits left of the point
217 * such that the representation is without exponent.
218 * This evaluates to <code>7</code> as specified for double's
219 * in {@link Double#toString(double)} and is used by
220 * {@link #BigDecimalRep(BigDecimal)}.
221 */
222 private static final int MAX_INT_DIGITS_NO_EXP = 7;
223
224 /* ---------------------------------------------------------------- *
225 * constructors. *
226 * ---------------------------------------------------------------- */
227
228 /**
229 * Constructs a newly allocated <code>BigDecimalRep</code>
230 * that represents given <code>BigDecimal</code> argument.
231 *
232 * @param dec
233 * the value to be represented
234 * by this <code>BigDecimalRep</code>.
235 */
236 @SuppressWarnings({"checkstyle:nowhitespacebefore",
237 "checkstyle:nowhitespaceafter"})
238 BigDecimalRep(BigDecimal dec) {
239 switch (dec.signum()) {
240 case -1:
241 this.sign = SIGN_MINUS;
242 dec = dec.abs();
243 break;
244 case 0:
245 //assert exp == 0;
246 this.sign = SIGN_PLUS;
247 this.integer = "0";
248 //this.mantissa ="0.0";
249 this.fraction = "0";
250 this.exponent = "";
251 return;
252 case 1:
253 this.sign = SIGN_PLUS;
254 break;
255 default:
256 throw new IllegalStateException
257 ("Found unexpected sign " + dec.signum() + ". ");
258 }
259 // Here, d is not zero, mantissa is not "0" and has no sign.
260
261 int exp = -dec.scale();
262 String mantissa = dec.unscaledValue().toString();
263
264 int lenMant = mantissa.length();
265 if (new BigDecimal("1.0e" + MAX_FRAC_DIGITS_NO_EXP).compareTo(dec)
266 <= 0 &&
267 new BigDecimal("1.0e" + MAX_INT_DIGITS_NO_EXP).compareTo(dec)
268 > 0) {
269 // the representation is xxx.yyy without exponent.
270 this.exponent = "";
271 if (BigDecimal.valueOf(1).compareTo(dec) > 0) {
272 // Here, 0 < d < 1.
273 mantissa = alignRight(mantissa,
274 1 - exp,
275 '0',
276 ALIGN_EXCEPTION);
277 }
278 // the representation xxx.yyy with nontrivial integer part.
279 this.integer = mantissa
280 . substring(0 , lenMant + exp);
281 this.fraction = mantissa
282 . substring(lenMant + exp, lenMant );
283 } else {
284 // representation a.yyyezzz with exponent
285 // where a is a digit != 0.
286 this.exponent = Integer
287 .toString(exp + lenMant - 1);
288 this.integer = mantissa.substring(0, 1);
289 this.fraction = mantissa.substring(1, lenMant);
290 }
291
292 // remove trailing zeros.
293 this.fraction = this.fraction.replaceFirst("0*$", "");
294 // add a zero if nothing else is left.
295 if (this.fraction.length() == 0) {
296 this.fraction = "0";
297 }
298 //this.mantissa =
299 // this.integer + POINT_S + this.fraction;
300 }
301
302 /**
303 * Constructs a newly allocated
304 * <code>BigDecimalRep</code> object
305 * that represents the floating-point value of type double
306 * represented by the string.
307 * The string is converted to a double value
308 * as if by the method {@link Double#valueOf}.
309 *
310 * @param dStr
311 * a string to be converted
312 * to a <code>BigDecimalRep</code>.
313 * @see Double#Double(String)
314 */
315 BigDecimalRep(String dStr) {
316 this(new BigDecimal(dStr));
317 }
318 } // class BigDecimalRep
319
320 /**
321 * Describes the representation of a double, resp. a Double-value.
322 * It is characterized
323 * by the {@link #mantissa} and the {@link #exponent}.
324 * The mantissa in turn
325 * splits into the {@link #integer} and the {@link #fraction}al part.
326 *
327 * @author <a href="mailto:e.reissner@rose.de">Ernst Reissner</a>
328 * @version 1.0
329 */
330 private static final class DoubleRep extends RealRepresentation {
331
332 /* ---------------------------------------------------------------- *
333 * constructors. *
334 * ---------------------------------------------------------------- */
335
336 /**
337 * Constructs a newly allocated
338 * <code>DoubleRep</code> object
339 * that represents the primitive <code>double</code> argument.
340 *
341 * @param dbl
342 * the value to be represented
343 * by this <code>DoubleRep</code>.
344 * @see Double#Double(double)
345 * @throws NumberFormatException
346 * if <code>d</code> is either infinite or not a number.
347 */
348 DoubleRep(double dbl) {
349
350 // Exclude that d is NaN or infinite
351 if (Double.isNaN(dbl) || Double.isInfinite(dbl)) {
352 // Replace dbl by |dbl|
353 // because of bug in constructor BigDecimal(double).
354 throw new NumberFormatException
355 ("For input string: \"" + Math.abs(dbl) + "\"");
356 }
357 // Here d is neither NaN nor infinite.
358
359 String str = Double.toString(dbl);
360 String mantissa;
361 int index;
362 index = str.indexOf('E');
363 if (index == -1) {
364 index = str.indexOf('e');
365 }
366 // Here, either index == -1 or index is the index of the exp.
367
368 if (index == -1) {
369 // Here, no exponent is given.
370 this.exponent = "";
371 mantissa = str;
372 } else {
373 // Here, an exponent is given.
374 this.exponent = str.substring(index + 1, str.length());
375 mantissa = str.substring(0, index);
376 initSignExp();
377 }
378 // Here, mantissa and exponent are separated
379 // and also str is not empty.
380
381 // extract sign (also think of the distinction -0.0 and +0.0).
382 Number2SignUnsigned sus = new Number2SignUnsigned(mantissa);
383 this.sign = sus.getSign();
384 mantissa = sus.getUnSigned();
385 // Here, str is the unsigned mantissa.
386
387 index = mantissa.indexOf(POINT_S);
388 if (index == -1) {
389 // no decimal point: mantissa is an integer.
390 // according to the docs of Double.toString(double)
391 // this does not occur, but...
392 throw new IllegalStateException
393 ("Unlike specified for Double.toString(double) " +
394 "found no decimal point in \"" + mantissa + "\". ");
395 }
396 this.integer = mantissa.substring(0, index);
397 this.fraction = mantissa.substring(index + 1,
398 mantissa.length());
399 // Here, mantissa is separated into integer and fraction.
400 }
401
402 /**
403 * Constructs a newly allocated
404 * <code>DoubleRep</code> object
405 * that represents the floating-point value of type double
406 * represented by the string.
407 * The string is converted to a double value
408 * as if by the method {@link Double#valueOf}.
409 *
410 * @param dStr
411 * a string to be converted
412 * to a <code>DoubleRep</code>.
413 * @see Double#Double(String)
414 * @throws IllegalArgumentException
415 * if <code>d</code> is either infinite or not a number.
416 * @throws NumberFormatException
417 * if <code>d</code> has not the appropriate number format.
418 */
419 DoubleRep(String dStr) {
420 this(Double.parseDouble(dStr));
421 }
422
423 /**
424 * Creates a new <code>DoubleRep</code>.
425 * An analog to {@link DoubleRep(double)}.
426 *
427 * @param dbl
428 * a <code>Double</code> object.
429 * @throws IllegalArgumentException
430 * if <code>d</code> is either infinite or not a number.
431 */
432 DoubleRep(Double dbl) {
433 this(dbl.doubleValue());
434 }
435
436 /* ---------------------------------------------------------------- *
437 * general methods. *
438 * ---------------------------------------------------------------- */
439
440 } // class DoubleRep
441
442 /**
443 * A <code>Cutter</code> is used to shorten numbers.
444 * This can either be done by cutting, by rounding or somenthing else.
445 */
446 public interface Cutter {
447 /**
448 * Returns a substring of <code>str</code>
449 * with length <code>len</code> or throws an exception.
450 *
451 * @param str
452 * a <code>String</code> with <code>str.length() >= len</code>.
453 * @param len
454 * the desired length of the resulting string.
455 * @return
456 * a substring of <code>str</code> with length <code>len</code>.
457 * @throws RuntimeException
458 * by need if the cut is not allowed.
459 */
460 String cut(String str, int len);
461 } // interface Cutter
462
463 /**
464 * Container for number splitted into sign and unsigned.
465 */
466 private static class Number2SignUnsigned {
467
468 /**
469 * The sign which is either {@link #SIGN_PLUS} or {@link #SIGN_MINUS}.
470 */
471 private final String sign;
472
473 /**
474 * The unsigned part of a number.
475 */
476 private final String unSigned;
477
478 /**
479 * Creates a new <code>Number2SignUnsigned</code> instance
480 * wrapping a string representation of a number.
481 *
482 * @param signed
483 * a <code>String</code> representation of a number.
484 * There may be either an explicit sign
485 * or the first symbol is a digit.
486 * @throws NumberFormatException
487 * if the first symbol is neither a sign nor a digit.
488 */
489 Number2SignUnsigned(String signed) {
490 // extract sign (also think of the distinction -0.0 and +0.0).
491 switch (signed.charAt(0)) {
492 case '+':
493 // explicit + sign
494 this.sign = SIGN_PLUS;
495 this.unSigned = signed.substring(1, signed.length());
496 break;
497 case '-':
498 // explicit - sign
499 this.sign = SIGN_MINUS;
500 this.unSigned = signed.substring(1, signed.length());
501 break;
502 default:
503 // implicit + sign
504 // Here, one should have some digit at the 0th place.
505 if (!signed.substring(0, 1).matches("\\d")) {
506 throw new NumberFormatException
507 ("Expected unsigned number found " + signed + ". ");
508 }
509 this.sign = SIGN_PLUS;
510 this.unSigned = signed;
511 }
512 }
513
514 String getSign() {
515 return this.sign;
516 }
517
518 String getUnSigned() {
519 return this.unSigned;
520 }
521
522 } // class Number2SignUnsigned
523
524
525 /**
526 * Describes the way
527 * the real number represented by {@link RealRepresentation}
528 * is displayed as a string.
529 */
530 public static class Desc {
531
532 /* ---------------------------------------------------------------- *
533 * fields. *
534 * ---------------------------------------------------------------- */
535
536 /**
537 * Signifies whether an attempt
538 * to cut off parts of the integer will result in an exception;
539 * otherwise it is just ignored.
540 */
541 @SuppressWarnings("PMD.FinalFieldCouldBeStatic")
542 @edu.umd.cs.findbugs.annotations.SuppressWarnings
543 (value = "SS_SHOULD_BE_STATIC",
544 justification = "not now")
545 private final boolean strictInteger = false;
546
547 /**
548 * Signifies whether an attempt
549 * to cut off parts of the exponent will result in an exception;
550 * otherwise it is just ignored.
551 */
552 @SuppressWarnings("PMD.FinalFieldCouldBeStatic")
553 @edu.umd.cs.findbugs.annotations.SuppressWarnings
554 (value = "SS_SHOULD_BE_STATIC",
555 justification = "not now")
556 private final boolean strictExponent = false;
557
558 private final Cutter fractionCutter = ALIGN_CUT_OFF_RIGHT;
559
560 /**
561 * The maximal length of the integer part of a number
562 * displayed in a specific column of the table.
563 */
564 private final int lenI;
565
566 /**
567 * The maximal length of the mantissa of a number
568 * displayed in a specific column of the table.
569 * @see #lenI
570 */
571 private final int lenM;
572
573 /**
574 * The maximal length of the exponent part of a number
575 * displayed in a specific column of the table.
576 * @see #lenI
577 */
578 private final int lenE;
579
580
581 /* ---------------------------------------------------------------- *
582 * constructors. *
583 * ---------------------------------------------------------------- */
584
585 // **** under construction.
586 public Desc(int lenI, int lenM, int lenE) {
587 this.lenI = lenI;
588 this.lenM = lenM;
589 this.lenE = lenE;
590 }
591 } // class Desc
592
593
594 /* -------------------------------------------------------------------- *
595 * fields. *
596 * -------------------------------------------------------------------- */
597
598 /**
599 * The sign of the double value represented.
600 * This may be either {@link #SIGN_PLUS +} or {@link #SIGN_MINUS -}.
601 * Note that the standard IEEE 754 distinguishes <code>-0</code>
602 * from <code>+0</code> and so do we in the subclass
603 * {@link RealRepresentation.DoubleRep}.
604 */
605 @SuppressWarnings("checkstyle:visibilitymodifier")
606 protected String sign;
607
608 /*
609 * The mantissa of the double value represented.
610 */
611 //protected String mantissa;
612
613 /**
614 * The integer part of the mantissa of the double value represented.
615 */
616 @SuppressWarnings("checkstyle:visibilitymodifier")
617 protected String integer;
618
619 /**
620 * The fractional part of the mantissa of the double value represented.
621 * This may never be empty but it may be <code>0</code>.
622 */
623 @SuppressWarnings("checkstyle:visibilitymodifier")
624 protected String fraction;
625
626
627 /**
628 * The exponent of the double value represented.
629 */
630 @SuppressWarnings("checkstyle:visibilitymodifier")
631 protected String exponent;
632
633 private String signOfExp; // NOPMD
634
635 private String unsignedExp; // NOPMD
636
637 /* -------------------------------------------------------------------- *
638 * create methods: out of Strings, doubles, Doubles and BigDecimals. *
639 * -------------------------------------------------------------------- */
640
641 @edu.umd.cs.findbugs.annotations.SuppressWarnings
642 (value = "URF_UNREAD_FIELD",
643 justification = "to be used in later versions ")
644 protected final void initSignExp() {
645 Number2SignUnsigned sus = new Number2SignUnsigned(this.exponent);
646 this.signOfExp = sus.getSign();
647 this.unsignedExp = sus.getUnSigned();
648 }
649
650 /**
651 * Converts the given string representation of a real number
652 * to a <code>RealRepresentation</code> with the given precision.
653 *
654 * @param val
655 * a <code>String</code> representation of a real number.
656 * @param precision
657 * a <code>boolean</code> which offers choice between
658 * full precision (<code>true</code>) and
659 * double precision (<code>false</code>).
660 * @return
661 * a <code>RealRepresentation</code> of the real value
662 * given by the string representation <code>val</code>
663 * with the precision determined by <code>precision</code>.
664 * @throws NumberFormatException
665 * if <code>val</code> is not the string representation of a double
666 * or if it is <code>NaN</code> or represents an infinite value.
667 */
668 public static RealRepresentation create(String val, boolean precision) {
669 return precision ? new BigDecimalRep(val) : new DoubleRep(val);
670 }
671
672 /**
673 * Converts the given high precision representation of a real number
674 * to a <code>RealRepresentation</code>
675 * preserving full precision if so specified.
676 *
677 * @param val
678 * a <code>Number</code> value
679 * which is either a {@link BigDecimal} or a <code>Double</code>.
680 * @param precision
681 * specifies whether to preserve full precision.
682 * If set to <code>false</code>
683 * only <code>double</code> precision is used.
684 * @return
685 * a <code>RealRepresentation</code> of the real value
686 * given by <code>val</code>
687 * preserving full precision is specified so.
688 * @throws ClassCastException
689 * if <code>val</code> is neither a {@link BigDecimal}
690 * nor a <code>Double</code>.
691 */
692 public static RealRepresentation create(Number val,
693 boolean precision) {
694 if (precision) {
695 return (val instanceof BigDecimal)
696 ? new BigDecimalRep( (BigDecimal) val )
697 : new DoubleRep(((Double ) val).doubleValue());
698 } else {
699 return new DoubleRep(val.doubleValue());
700 }
701 }
702
703 /**
704 * Converts the given <code>double</code> number
705 * to a <code>RealRepresentation</code> with the given precision.
706 *
707 * @param val
708 * a <code>double</code> value.
709 * @param precision
710 * a <code>boolean</code> which offers choice between
711 * full precision (<code>true</code> which is obsolete****) and
712 * double precision (<code>false</code>).
713 * @return
714 * a <code>RealRepresentation</code> of the given <code>double</code>
715 * with the precision determined by <code>precision</code>.
716 * @throws NumberFormatException
717 * if <code>val</code> is either <code>NaN</code> or infinite.
718 */
719 public static RealRepresentation create(double val,
720 boolean precision) {
721 return create(Double.valueOf(val), precision);
722 }
723
724 /**
725 * Converts the given number
726 * to a <code>RealRepresentation</code> with the natural precision.
727 *
728 * @param val
729 * a <code>Number</code> value
730 * which is either a {@link BigDecimal} or a <code>Double</code>.
731 * @return
732 * a <code>RealRepresentation</code> of the given number
733 * with the natural precision:
734 * <code>create((BigDecimal)val, true)</code> or
735 * <code>create((Double )val, true)</code>.
736 * @throws ClassCastException
737 * if <code>val</code> is neither a {@link BigDecimal}
738 * nor a <code>Double</code>.
739 */
740 public static RealRepresentation create(Number val) {
741 return val instanceof BigDecimal
742 ? create((BigDecimal) val, true)
743 : create((Double ) val, false);
744 }
745
746 /* -------------------------------------------------------------------- *
747 * methods for aligning strings. *
748 * -------------------------------------------------------------------- */
749
750 /**
751 * Returns a <code>String</code>
752 * consisting of <code>len</code> copies of the character <code>c</code>.
753 *
754 * @param chr0
755 * a <code>char</code>.
756 * @param len
757 * the number of repetitions of <code>c</code> needed.
758 * This should be a non-negative integer.
759 * @return
760 * a <code>String</code> consisting of <code>len</code> characters
761 * <code>c</code>.
762 */
763 public static String fill(char chr0, int len) {
764 Character chr = Character.valueOf(chr0);
765 String cutString = FILL_STRINGS.get(chr);
766 // by contract, cutString is either null or
767 // its length is 2^n for some natural number n.
768 boolean copyBack = false;
769 if (cutString == null) {
770 cutString = chr.toString(); //Character.toString(c);
771 copyBack = true;
772 }
773
774 // Here, cutString != null && cutString.length() > 0
775
776 if (cutString.length() < len) {
777 copyBack = true;
778 StringBuffer cutBuf = new StringBuffer(cutString);
779 while (cutBuf.length() < len) {
780 cutBuf.append(cutBuf);
781 }
782 cutString = cutBuf.toString();
783 }
784
785 // Here, cutString != null && cutString.length() >= len
786 if (copyBack) {
787 FILL_STRINGS.put(chr, cutString);
788 }
789 // Here, (String)FILL_STRINGS.get(chr).equals(cutString) again.
790
791 return cutString.substring(0, len);
792 }
793
794 /**
795 * Returns a <code>String</code> which is
796 * by attaching the minimal number of <code>filler</code>s
797 * to the right hand side of <code>str</code>
798 * such that the length of the result is at least <code>int</code>.
799 * For <code>strict == true</code> even equality is assured.
800 *
801 * @param str
802 * the <code>String</code> to be aligned.
803 * @param len
804 * an <code>int</code> value which determines
805 * the length of the result string:
806 * @param filler
807 * a <code>char</code> value.
808 * @param cutter
809 * takes effect if <code>str.length > len</code>:
810 * <ul>
811 * <li>
812 * for {@link #ALIGN_CUT_OFF_RIGHT} superfluous digits are cut off,
813 * <li> {
814 * for {@link #ALIGN_EXCEPTION} superfluous digits cause an exception,
815 * <li>
816 * for {@link #ALIGN_LEAVE_UNCHANGED}
817 * superfluous digits are left unchanged,
818 * </ul>
819 * @return
820 * <ul>
821 * <li> for <code>str.length()≤len</code>
822 * copies of <code>filler</code>s
823 * are attached to the right hand side of <code>str</code>
824 * such that the length of the result is least <code>int</code>.
825 * <li> for <code>str.length()>len</code>
826 * <ul>
827 * <li>
828 * <code>str</code> is returned as is
829 * provided <code>cutter == {@link #ALIGN_LEAVE_UNCHANGED}</code>
830 * <li>
831 * For <code>cutter == {@link #ALIGN_EXCEPTION}</code>
832 * there is no return value:
833 * an exception is thrown and finally
834 * <li>
835 * for <code>cutter == {@link #ALIGN_CUT_OFF_RIGHT}</code>
836 * the overhead is silently cut off.
837 * </ul>
838 * </ul>
839 * @throws IllegalArgumentException
840 * for <code>cutter == {@link #ALIGN_EXCEPTION}</code>
841 * if <code>str.length()</code> exceeds <code>len</code>.
842 */
843 public static String alignLeft(String str,
844 int len,
845 char filler,
846 Cutter cutter) {
847 int strLen = str.length();
848 return strLen > len
849 ? cutter.cut(str, len)
850 : str + fill(filler, len - strLen);
851 }
852
853 /**
854 * Returns a <code>String</code> which is
855 * by attaching the minimal number of <code>filler</code>s
856 * to the left hand side of <code>str</code>
857 * such that the length of the result is at least <code>int</code>.
858 * For <code>strict == true</code> even equality is assured.
859 *
860 * @param str
861 * the <code>String</code> to be aligned.
862 * @param len
863 * an <code>int</code> value which determines
864 * the length of the result string:
865 * @param filler
866 * a <code>char</code> value.
867 * @param cutter
868 * takes effect if <code>str.length > len</code>: { {
869 * <ul>
870 * <li>
871 * for {@link #ALIGN_CUT_OFF_LEFT} superfluous digits are cut off,
872 * <li>
873 * for {@link #ALIGN_EXCEPTION} superfluous digits cause an exception,
874 * <li>
875 * for {@link #ALIGN_LEAVE_UNCHANGED}
876 * superfluous digits are left unchanged,
877 * </ul>
878 * @return
879 * <ul>
880 * <li> for <code>str.length()≤len</code>
881 * copies of <code>filler</code>s
882 * are attached to the right hand side of <code>str</code>
883 * such that the length of the result is least <code>int</code>.
884 * <li> for <code>str.length()>len</code>
885 * <ul>
886 * <li>
887 * <code>str</code> is returned as is
888 * provided <code>cutter == {@link #ALIGN_LEAVE_UNCHANGED}</code>
889 * <li>
890 * For <code>cutter == {@link #ALIGN_EXCEPTION}</code>
891 * there is no return value:
892 * an exception is thrown and finally
893 * <li>
894 * for <code>cutter == {@link #ALIGN_CUT_OFF_LEFT}</code>
895 * the overhead is silently cut off.
896 * </ul>
897 * </ul>
898 * @throws IllegalArgumentException
899 * for <code>cutter == {@link #ALIGN_EXCEPTION}</code>
900 * if <code>str.length()</code> exceeds <code>len</code>.
901 */
902 public static String alignRight(String str,
903 int len,
904 char filler,
905 Cutter cutter) {
906 int strLen = str.length();
907 return strLen > len
908 ? cutter.cut(str, len)
909 : fill(filler, len - strLen) + str;
910 }
911
912 /* -------------------------------------------------------------------- *
913 * trim and cut methods. *
914 * -------------------------------------------------------------------- */
915
916 /*
917 private void updateMantissa() {
918 this.mantissa =
919 this.integer +
920 (hasFraction() ? POINT_S : noPointS) +
921 this.fraction;
922 }
923 */
924
925 // **** for align methods: message of exception
926 // Cannot trim integer " + this.integer + " to " + numDigits + " digits. "
927 // better than current one.
928 /**
929 * Trims the integer part
930 * to length <code>numDigits</code> if possible.
931 * If this leads to a prolongation of the integer part,
932 * it is filled up with characters <code>blankOrNull</code>
933 * from the left hand side.
934 * If the integer part is already longer than specified,
935 * the action taken relies on the parameter <code>strict</code>.
936 * Caution: ***** this does not work very well
937 * for <code>numDigits = 0</code>.
938 * Caution: **** not ok with signs.
939 * Caution: **** what to do if ".4" is needed?
940 *
941 * @param numDigits
942 * a non-negative <code>int</code> value signifying the length
943 * of the integer part.
944 * @param blankOrNull
945 * a <code>char</code> with which the integer part is filled up
946 * by need from the left hand side
947 * to reach length <code>numDigits</code>.
948 * Useful settings are probably blank and <code>'0'</code> only.
949 * @param strict
950 * a <code>boolean</code> signifying whether an attempt
951 * to cut off parts of the integer will result in an exception;
952 * otherwise it is just ignored.
953 * @return
954 * the new integer part as a <code>String</code>.
955 * @throws IllegalArgumentException
956 * for <code>strict( == true)</code>
957 * if the length of the integer part exceeds <code>numDigits</code>.
958 */
959 public final String trimInteger(int numDigits,
960 char blankOrNull,
961 boolean strict) {
962 Cutter cutter = strict ? ALIGN_EXCEPTION : ALIGN_LEAVE_UNCHANGED;
963 this.integer = alignRight(this.integer,
964 numDigits,
965 blankOrNull,
966 cutter);
967 //updateMantissa();
968 return this.integer;
969 }
970
971 /**
972 * Trims the exponent part
973 * to length <code>numDigits</code> if possible.
974 * If this leads to a prolongation of the exponent part,
975 * it is filled up with characters <code>blankOrNull</code>
976 * from the left hand side.
977 * If the exponent part is already longer than specified,
978 * the action taken relies on the parameter <code>strict</code>.
979 * Caution: ***** this does not work very well
980 * for <code>numDigits = 0</code>.
981 * Caution: **** not ok with signs.
982 * Caution: **** not ok if there are no exponents at all.
983 *
984 * @param numDigits
985 * a non-negative <code>int</code> value signifying the length
986 * of the exponent part.
987 * @param blankOrNull
988 * a <code>char</code> with which the exponent part is filled up
989 * by need from the left hand side
990 * to reach length <code>numDigits</code>.
991 * Useful settings are probably blank and <code>'0'</code> only.
992 * @param strict
993 * a <code>boolean</code> signifying whether an attempt
994 * to cut off parts of the exponent will result in an exception;
995 * otherwise it is just ignored.
996 * @return
997 * the new exponent as a <code>String</code>.
998 * @throws IllegalArgumentException
999 * for <code>strict( == true)</code>
1000 * if the length of the exponent part exceeds <code>numDigits</code>.
1001 */
1002 public final String trimExponent(int numDigits,
1003 char blankOrNull,
1004 boolean strict) {
1005 Cutter cutter = strict ? ALIGN_EXCEPTION : ALIGN_LEAVE_UNCHANGED;
1006 this.exponent = alignRight(this.exponent,
1007 numDigits,
1008 blankOrNull,
1009 cutter);
1010 return this.exponent;
1011 }
1012
1013 /**
1014 * Trims the fractional part
1015 * to length <code>numDigits</code> if possible.
1016 * If this leads to a prolongation of the fractional part,
1017 * it is filled up with characters <code>blankOrNull</code>.
1018 * If the fractional part is already longer than specified,
1019 * the action taken relies on the code <code>cutter</code>.
1020 * Caution: ***** this does not work very well
1021 * for <code>numDigits = 0</code>.
1022 * Caution: **** this method simply cuts off digits
1023 * without rounding.
1024 *
1025 * @param numDigits
1026 * a non-negative <code>int</code> value signifying the length
1027 * of the fractional part.
1028 * @param blankOrNull
1029 * a <code>char</code> with which the fractional part is filled up
1030 * by need to reach length <code>numDigits</code>.
1031 * Useful settings are probably <code>'0'</code> and blank only.
1032 * @param cutter
1033 * an <code>int</code> code which is relevant only,
1034 * if the current fractional part is longer
1035 * than specified by <code>numDigits</code>.
1036 * @return
1037 * the new trimmed fractional part as a <code>String</code>.
1038 * @throws IllegalArgumentException
1039 * for <code>cutter == {@link #ALIGN_EXCEPTION}</code>
1040 * if the length of the fractional part
1041 * exceeds <code>numDigits</code>.
1042 */
1043 public final String trimFraction(int numDigits,
1044 char blankOrNull,
1045 Cutter cutter) {
1046 this.fraction =
1047 alignLeft(this.fraction, numDigits, blankOrNull, cutter);
1048 //updateMantissa();
1049 return this.fraction;
1050 }
1051
1052 /* -------------------------------------------------------------------- *
1053 * representation methods. *
1054 * -------------------------------------------------------------------- */
1055
1056 /**
1057 * Converts this representation such that
1058 * there is neither a {@link #fraction} nor an {@link #exponent}.
1059 * Of course in general thereby the current format is lost.
1060 *
1061 * @throws NumberFormatException
1062 * if this representation cannot be written as an integer.
1063 */
1064 public final void asInteger() {
1065 String trimmedExponent = this.exponent.trim();
1066 BigInteger expVal = "".equals(trimmedExponent)
1067 ? BigInteger.ZERO
1068 : new BigInteger(trimmedExponent);
1069 // remove trailing 0's and blanks.
1070 String trimmedFraction = this.fraction.replaceAll("0* *$", "");
1071 expVal = expVal.subtract
1072 (new BigInteger(Integer.toString(trimmedFraction.length())));
1073 this.integer += trimmedFraction;
1074 // Here the representation this.integer.0EexpVal is without fraction.
1075
1076 this.integer = this.integer.replaceAll("^[0 ]*", "");
1077 if (this.integer.equals("")) { // also possible with "" but to dangerous
1078 this.integer = "0";
1079 }
1080 // Here, this.integer has no leading 0's or blanks.
1081
1082 switch (expVal.signum()) {
1083 case -1:
1084 throw new NumberFormatException
1085 ("Could not represent " + this + " as an integer. ");
1086 case 0:
1087 // nothing to do: representation is already without exponent.
1088 break;
1089 case 1:
1090 this.integer += fill('0', expVal.intValue());
1091 break;
1092 default:
1093 throw new IllegalStateException
1094 ("Found signum " + expVal.signum()
1095 + " which may be only -1, 0 or 1. ");
1096 }
1097
1098 this.fraction = "";
1099 this.exponent = "";
1100 }
1101
1102 /* -------------------------------------------------------------------- *
1103 * get methods. *
1104 * -------------------------------------------------------------------- */
1105
1106 public final boolean hasBlankFraction() {
1107 return !this.fraction.matches("^ *$");
1108 }
1109
1110 public final boolean hasFraction() {
1111 return !this.fraction.matches("^0* *$");
1112 }
1113
1114 public final boolean hasInteger() {
1115 return !this.integer.matches("^ *0*$");
1116 }
1117
1118 public final boolean hasExponent() {
1119 return !this.exponent.matches("^ *$");
1120 }
1121
1122 public final String sign() {
1123 return this.sign;
1124 }
1125
1126 public final String exponent() {
1127 return this.exponent;
1128 }
1129
1130 public final String mantissa() {
1131 return this.integer +
1132 (hasBlankFraction() ? POINT_S : noPointS) +
1133 this.fraction;
1134
1135 //return this.mantissa;
1136 }
1137
1138 public final String integer() {
1139 return this.integer;
1140 }
1141
1142 public final String fraction() {
1143 return this.fraction;
1144 }
1145
1146 /* -------------------------------------------------------------------- *
1147 * inverse create methods: *
1148 * retrieve Strings, doubles, Doubles and BigDecimals. *
1149 * -------------------------------------------------------------------- */
1150
1151 /**
1152 * Returns a <code>Double</code> represented.
1153 *
1154 * @return
1155 * a <code>Double</code> <code>d</code> satisfying
1156 * {@link #create(Number, boolean)
1157 * create(d, false).this2Double().compareTo(d) == 0}.
1158 */
1159 public final Double this2Double() {
1160 return Double.valueOf(this.sign + mantissa() + getExpWithE());
1161 }
1162
1163 /**
1164 * Returns a <code>double</code> represented.
1165 *
1166 * @return
1167 * a <code>double</code> <code>d</code> satisfying
1168 * {@link #create(double, boolean) create(d, false).this2double() == d}.
1169 */
1170 public final double this2double() {
1171 return this2Double().doubleValue();
1172 }
1173
1174 /**
1175 * Returns a <code>BigDecimal</code> represented.
1176 *
1177 * @return
1178 * a <code>BigDecimal</code> <code>d</code> satisfying
1179 * {@link #create(Number, boolean)
1180 * create(d, true).this2BigDecimal().compareTo(d) == 0}.
1181 */
1182 public final BigDecimal this2BigDecimal() {
1183 //**** this does not work with trimmed mantissas
1184 return new BigDecimal(this.sign + mantissa() + getExpWithE());
1185 }
1186
1187 private String getExpWithE() {
1188 return this.exponent.equals("") ? "" : EXP_CHAR + this.exponent;
1189 }
1190
1191 /**
1192 * Returns a String representation of this real number.
1193 * Formatting is determined by previous invocations of the methods
1194 * {@link #trimInteger}, {@link #trimFraction} and {@link #trimExponent}.
1195 *
1196 * @return
1197 * a <code>String</code> reflecting this representation
1198 * of a real number.
1199 * In front of the sign (which may be empty),
1200 * between the sign and the integer part,
1201 * between the fractional part
1202 * and the exponent or the end of the string
1203 * and also between the *****
1204 * @see #toStringDecomp
1205 */
1206 public final String toString() {
1207 return
1208 (this.sign == SIGN_PLUS ? "" : this.sign) +
1209 mantissa() +
1210 (hasExponent() ? "e" : "") + exponent();
1211 }
1212
1213 public final String toString(Desc desc) {
1214
1215 trimInteger (desc.lenI, ' ', desc.strictInteger);
1216 trimFraction(desc.lenM -
1217 desc.lenI, ' ', desc.fractionCutter);
1218 trimExponent(desc.lenE, ' ', desc.strictExponent);
1219
1220 return
1221 (this.sign == SIGN_PLUS ? "" : this.sign) +
1222 mantissa() +
1223 (hasExponent() ? "E" : " ") + exponent();
1224 }
1225
1226 /**
1227 * Returns a string showing the decomposition of the underlying real number
1228 * into sign, mantissa and exponent.
1229 *
1230 * @return a <code>String</code> value
1231 * @see #toString
1232 */
1233 public final String toStringDecomp() {
1234 return
1235 "sign: " + this.sign + "\n" +
1236 "integer: " + this.integer + "\n" +
1237 "fraction: " + this.fraction + "\n" +
1238 "exponent: " + this.exponent;
1239 }
1240 }