001/**
002 * NumericPrecision.java
003 *
004 * Copyright (c) 2004-2012, Nicole C. Tedesco.  All rights reserved.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at:
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package net.sf.jaccumulator.scalars;
020
021import java.math.BigDecimal;
022import java.math.BigInteger;
023import java.util.IdentityHashMap;
024import java.util.Map;
025import java.util.concurrent.atomic.AtomicBoolean;
026import java.util.concurrent.atomic.AtomicInteger;
027import java.util.concurrent.atomic.AtomicLong;
028
029/**
030 * Non-UML semantic lemma that define numeric implementation precision, or
031 * implied total digits of any radix.<br/>
032 * <br/>
033 * All computer numbers are implemented using boolean vectors, the number of
034 * significant digits representable being roughly dependent upon the
035 * <i>known</i> {@link #size() size} of the implementing vector (bit
036 * count). Generally, "known" implies that it is more precise to <i>know</i>
037 * that zero digits are available than to not know at all which in turn implies
038 * that {@link #UNKNOWN} is <i>less</i> precise than {@link #NULL} which is a
039 * known precision (vector size of zero). {@link #isUnlimited() Unlimited}
040 * numbers however do not have known digit counts at design time but definitely
041 * have known digit counts at runtime so are said to be of higher precision than
042 * {@code UNKNOWN} and are, in fact, the highest since their <i>possible</i>
043 * digit counts are <i>known</i> to be for all practical purposes unlimited.
044 *
045 * @since JAccumulator 4.0
046 * @author Nicole Tedesco (<a
047 *         href="mailto:Nicole@NicoleTedesco.com">Nicole@NicoleTedesco.com</a>)
048 */
049public enum NumericPrecision
050{
051    /**
052     * <b>Unknown</b> precision, which is even less precise than {@link #NULL}
053     * (empty set)
054     */
055    UNKNOWN( String.class, String.class ) { /* 0 */
056        @Override
057        public final int compare( final NumericPrecision prec ) {
058            return -1;
059        }
060
061        @Override
062        public final int size() {
063            return -1;
064        }
065
066        @Override
067        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
068            return false;
069        }
070
071        @Override
072        public final boolean isFinite() {
073            return false;
074        }
075
076        @Override
077        public final boolean isFloatingPoint() {
078            return false;
079        }
080
081        @Override
082        public final boolean isIeee754() {
083            return false;
084        }
085
086        @Override
087        public final boolean isIntegral() {
088            return false;
089        }
090
091        @Override
092        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
093            return prec != this;
094        }
095
096        @Override
097        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
098            return false;
099        }
100
101        @Override
102        public final boolean isNumeric() {
103            return false;
104        }
105
106        @Override
107        public final boolean isSigned() {
108            return false;
109        }
110
111        @Override
112        public final boolean isUnlimited() {
113            return false;
114        }
115
116        @Override
117        public final NumericPrecision promote() {
118            return UNKNOWN;
119        }
120
121        @Override
122        public final NumericPrecision promoteAgainst(
123            final NumericPrecision prec )
124        {
125            return prec;
126        }
127
128        @Override
129        public final NumericPrecision toFloatingPoint() {
130            return UNKNOWN;
131        }
132    },
133
134    /**
135     * No numeric domain, or the <b>empty set</b> (no digits, not even {@code 0}
136     * , though its field cardinality is 0)
137     */
138    NULL( Void.class, Void.TYPE ) { /* 1 */
139        @Override
140        public final int compare( final NumericPrecision prec ) {
141            if (prec == this) {
142                return 0;
143            }
144            if (prec == UNKNOWN) {
145                return +1;
146            }
147            return -1;
148        }
149
150        @Override
151        public final int size() {
152            return 0;
153        }
154
155        @Override
156        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
157            return prec == this;
158        }
159
160        @Override
161        public final boolean isFinite() {
162            return true;
163        }
164
165        @Override
166        public final boolean isFloatingPoint() {
167            return false;
168        }
169
170        @Override
171        public final boolean isIeee754() {
172            return false;
173        }
174
175        @Override
176        public final boolean isIntegral() {
177            return false;
178        }
179
180        @Override
181        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
182            return this.ordinal() < prec.ordinal();
183        }
184
185        @Override
186        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
187            return prec == UNKNOWN;
188        }
189
190        @Override
191        public final boolean isNumeric() {
192            return false;
193        }
194
195        @Override
196        public final boolean isSigned() {
197            return false;
198        }
199
200        @Override
201        public final boolean isUnlimited() {
202            return false;
203        }
204
205        @Override
206        public final NumericPrecision promote() {
207            return BIT;
208        }
209
210        @Override
211        public final NumericPrecision promoteAgainst(
212            final NumericPrecision prec )
213        {
214            return this.isLessPreciseThan(prec) ? prec : this;
215        }
216
217        @Override
218        public final NumericPrecision toFloatingPoint() {
219            return FLOAT;
220        }
221    },
222
223    /**
224     * <b>Boolean</b> domain which includes {@code 0} and {@link 1} (field
225     * cardinality is 2)
226     */
227    BIT( Boolean.class, boolean.class ) { /* 2 */
228        @Override
229        public final int compare( final NumericPrecision prec ) {
230            if (prec == this) {
231                return 0;
232            }
233            if (this.isLessPreciseThan(prec)) {
234                return -1;
235            }
236            return +1;
237        }
238
239        @Override
240        public final int size() {
241            return 1;
242        }
243
244        @Override
245        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
246            return prec == this;
247        }
248
249        @Override
250        public final boolean isFinite() {
251            return true;
252        }
253
254        @Override
255        public final boolean isFloatingPoint() {
256            return false;
257        }
258
259        @Override
260        public final boolean isIeee754() {
261            return false;
262        }
263
264        @Override
265        public final boolean isIntegral() {
266            return true;
267        }
268
269        @Override
270        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
271            return this.ordinal() < prec.ordinal();
272        }
273
274        @Override
275        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
276            return prec.ordinal() < this.ordinal();
277        }
278
279        @Override
280        public final boolean isNumeric() {
281            return true;
282        }
283
284        @Override
285        public final boolean isSigned() {
286            return false;
287        }
288
289        @Override
290        public final boolean isUnlimited() {
291            return false;
292        }
293
294        @Override
295        public final NumericPrecision promote() {
296            return BYTE;
297        }
298
299        @Override
300        public final NumericPrecision promoteAgainst(
301            final NumericPrecision prec )
302        {
303            return this.isLessPreciseThan(prec) ? prec : this;
304        }
305
306        @Override
307        public final NumericPrecision toFloatingPoint() {
308            return FLOAT;
309        }
310    },
311
312    /**
313     * <b>Byte</b> field, or 8 bits, for a total value count (field cardinality)
314     * of 2<sup>8</sup> and a <i>signed</i> value range of <span
315     * style="white-space=nowrap">-2<sup>7</sup></span> to <span
316     * style="white-space=nowrap">2<sup>7</sup>-1</span>
317     */
318    BYTE( Byte.class, byte.class ) { /* 3 */
319        @Override
320        public final int compare( final NumericPrecision prec ) {
321            if (prec == this) {
322                return 0;
323            }
324            if (this.isLessPreciseThan(prec)) {
325                return -1;
326            }
327            return +1;
328        }
329
330        @Override
331        public final int size() {
332            return Byte.SIZE;
333        }
334
335        @Override
336        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
337            return prec == this;
338        }
339
340        @Override
341        public final boolean isFinite() {
342            return true;
343        }
344
345        @Override
346        public final boolean isFloatingPoint() {
347            return false;
348        }
349
350        @Override
351        public final boolean isIeee754() {
352            return false;
353        }
354
355        @Override
356        public final boolean isIntegral() {
357            return true;
358        }
359
360        @Override
361        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
362            return this.ordinal() < prec.ordinal();
363        }
364
365        @Override
366        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
367            return prec.ordinal() < this.ordinal();
368        }
369
370        @Override
371        public final boolean isNumeric() {
372            return true;
373        }
374
375        @Override
376        public final boolean isSigned() {
377            return true;
378        }
379
380        @Override
381        public final boolean isUnlimited() {
382            return false;
383        }
384
385        @Override
386        public final NumericPrecision promote() {
387            return SHORT;
388        }
389
390        @Override
391        public final NumericPrecision promoteAgainst(
392            final NumericPrecision prec )
393        {
394            return this.isLessPreciseThan(prec) ? prec : this;
395        }
396
397        @Override
398        public final NumericPrecision toFloatingPoint() {
399            return FLOAT;
400        }
401    },
402
403    /**
404     * <b>Short</b> field, or two {@link #BYTE bytes}, for a total value count
405     * (field cardinality) of 2<sup>16</sup> and a <i>signed</i> value range of
406     * <span style="white-space=nowrap">-2<sup>15</sup></span> to <span
407     * style="white-space=nowrap">2<sup>15</sup>-1</span>
408     */
409    SHORT( Short.class, short.class ) { /* 4 */
410        @Override
411        public final int compare( final NumericPrecision prec ) {
412            if (this.isEquallyPreciseAs(prec)) {
413                return 0;
414            }
415            if (this.isLessPreciseThan(prec)) {
416                return -1;
417            }
418            return +1;
419        }
420
421        @Override
422        public final int size() {
423            return Short.SIZE;
424        }
425
426        @Override
427        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
428            return (prec == this) || (prec == CHARACTER);
429        }
430
431        @Override
432        public final boolean isFinite() {
433            return true;
434        }
435
436        @Override
437        public final boolean isFloatingPoint() {
438            return false;
439        }
440
441        @Override
442        public final boolean isIeee754() {
443            return false;
444        }
445
446        @Override
447        public final boolean isIntegral() {
448            return true;
449        }
450
451        @Override
452        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
453            return CHARACTER.ordinal() < prec.ordinal();
454        }
455
456        @Override
457        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
458            return prec.ordinal() < this.ordinal();
459        }
460
461        @Override
462        public final boolean isNumeric() {
463            return true;
464        }
465
466        @Override
467        public final boolean isSigned() {
468            return true;
469        }
470
471        @Override
472        public final boolean isUnlimited() {
473            return false;
474        }
475
476        @Override
477        public final NumericPrecision promote() {
478            return INTEGER;
479        }
480
481        @Override
482        public final NumericPrecision promoteAgainst(
483            final NumericPrecision prec )
484        {
485            return this.isLessPreciseThan(prec) ? prec : this;
486        }
487
488        @Override
489        public final NumericPrecision toFloatingPoint() {
490            return FLOAT;
491        }
492    },
493
494    /**
495     * Unsigned <b>character</b> field with the same bit count as {@link #SHORT}
496     * , so it shares both its cardinality (2<sup>16</sup>) and precision,
497     * though its <i>unsigned</i> value range is <span
498     * style="white-space=nowrap">0</span> to <span
499     * style="white-space=nowrap">2<sup>16</sup>-1</span>
500     */
501    CHARACTER( Character.class, char.class ) { /* 5 */
502        @Override
503        public final int compare( final NumericPrecision prec ) {
504            if (this.isEquallyPreciseAs(prec)) {
505                return 0;
506            }
507            if (this.isLessPreciseThan(prec)) {
508                return -1;
509            }
510            return +1;
511        }
512
513        @Override
514        public final int size() {
515            return Character.SIZE;
516        }
517
518        @Override
519        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
520            return (prec == this) || (prec == SHORT);
521        }
522
523        @Override
524        public final boolean isFinite() {
525            return true;
526        }
527
528        @Override
529        public final boolean isFloatingPoint() {
530            return false;
531        }
532
533        @Override
534        public final boolean isIeee754() {
535            return false;
536        }
537
538        @Override
539        public final boolean isIntegral() {
540            return true;
541        }
542
543        @Override
544        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
545            return this.ordinal() < prec.ordinal();
546        }
547
548        @Override
549        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
550            return prec.ordinal() < SHORT.ordinal();
551        }
552
553        @Override
554        public final boolean isNumeric() {
555            return true;
556        }
557
558        @Override
559        public final boolean isSigned() {
560            return false;
561        }
562
563        @Override
564        public final boolean isUnlimited() {
565            return false;
566        }
567
568        @Override
569        public final NumericPrecision promote() {
570            return INTEGER;
571        }
572
573        @Override
574        public final NumericPrecision promoteAgainst(
575            final NumericPrecision prec )
576        {
577            return this.isLessPreciseThan(prec) ? prec : this;
578        }
579
580        @Override
581        public final NumericPrecision toFloatingPoint() {
582            return FLOAT;
583        }
584    },
585
586    /**
587     * <b>Integer</b> field, or 4 bytes (32 bits), for a total value count
588     * (field cardinality) of 2<sup>32</sup> and a value range of <span
589     * style="white-space=nowrap">-2<sup>31</sup></span> to <span
590     * style="white-space=nowrap">2<sup>31</sup>-1</span>
591     */
592    INTEGER( Integer.class, int.class ) { /* 6 */
593        @Override
594        public final int compare( final NumericPrecision prec ) {
595            if (prec == this) {
596                return 0;
597            }
598            if (this.isLessPreciseThan(prec)) {
599                return -1;
600            }
601            return +1;
602        }
603
604        @Override
605        public final int size() {
606            return Integer.SIZE;
607        }
608
609        @Override
610        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
611            return prec == this;
612        }
613
614        @Override
615        public final boolean isFinite() {
616            return true;
617        }
618
619        @Override
620        public final boolean isFloatingPoint() {
621            return false;
622        }
623
624        @Override
625        public final boolean isIeee754() {
626            return false;
627        }
628
629        @Override
630        public final boolean isIntegral() {
631            return true;
632        }
633
634        @Override
635        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
636            return this.ordinal() < prec.ordinal();
637        }
638
639        @Override
640        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
641            return prec.ordinal() < this.ordinal();
642        }
643
644        @Override
645        public final boolean isNumeric() {
646            return true;
647        }
648
649        @Override
650        public final boolean isSigned() {
651            return true;
652        }
653
654        @Override
655        public final boolean isUnlimited() {
656            return false;
657        }
658
659        @Override
660        public final NumericPrecision promote() {
661            return LONG;
662        }
663
664        @Override
665        public final NumericPrecision promoteAgainst(
666            final NumericPrecision prec )
667        {
668            return this.isLessPreciseThan(prec) ? prec : this;
669        }
670
671        @Override
672        public final NumericPrecision toFloatingPoint() {
673            return FLOAT;
674        }
675    },
676
677    /**
678     * <b>Integer</b> field, or 8 bytes (64 bits), for a total value count
679     * (field cardinality) of 2<sup>64</sup> and a value range of <span
680     * style="white-space=nowrap">-2<sup>63</sup></span> to <span
681     * style="white-space=nowrap">2<sup>63</sup>-1</span>
682     */
683    LONG( Long.class, long.class ) { /* 7 */
684        @Override
685        public final int compare( final NumericPrecision prec ) {
686            if (prec == this) {
687                return 0;
688            }
689            if (this.isLessPreciseThan(prec)) {
690                return -1;
691            }
692            return +1;
693        }
694
695        @Override
696        public final int size() {
697            return Long.SIZE;
698        }
699
700        @Override
701        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
702            return prec == this;
703        }
704
705        @Override
706        public final boolean isFinite() {
707            return true;
708        }
709
710        @Override
711        public final boolean isFloatingPoint() {
712            return false;
713        }
714
715        @Override
716        public final boolean isIeee754() {
717            return false;
718        }
719
720        @Override
721        public final boolean isIntegral() {
722            return true;
723        }
724
725        @Override
726        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
727            return this.ordinal() < prec.ordinal();
728        }
729
730        @Override
731        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
732            return prec.ordinal() < this.ordinal();
733        }
734
735        @Override
736        public final boolean isNumeric() {
737            return true;
738        }
739
740        @Override
741        public final boolean isSigned() {
742            return true;
743        }
744
745        @Override
746        public final boolean isUnlimited() {
747            return false;
748        }
749
750        @Override
751        public final NumericPrecision promote() {
752            return UNLIMITED_INTEGER;
753        }
754
755        @Override
756        public final NumericPrecision promoteAgainst(
757            final NumericPrecision prec )
758        {
759            if (prec == FLOAT) return DOUBLE;
760            return this.isLessPreciseThan(prec) ? prec : this;
761        }
762
763        @Override
764        public final NumericPrecision toFloatingPoint() {
765            return DOUBLE;
766        }
767    },
768
769    /**
770     * IEEE <a href="http://en.wikipedia.org/wiki/Ieee_float">754-2008</a>
771     * single precision {@code float} value (32 bits). Though, strictly
772     * speaking, the value field size is actually smaller than that of a 32 bit
773     * {@link #INTEGER integer} due to the {@code float}'s 23 bit <a
774     * href="http://en.wikipedia.org/wiki/Significand">significand</a> size,
775     * {@code float} is treated as a <i>more</i> precise value because of its
776     * significantly increased minimum-to-maximum value range.
777     */
778    FLOAT( Float.class, float.class ) { /* 8 */
779        @Override
780        public final int compare( final NumericPrecision prec ) {
781            if (prec == this) {
782                return 0;
783            }
784            if (this.isLessPreciseThan(prec)) {
785                return -1;
786            }
787            return +1;
788        }
789
790        @Override
791        public final int size() {
792            return Float.SIZE;
793        }
794
795        @Override
796        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
797            return prec == this;
798        }
799
800        @Override
801        public final boolean isFinite() {
802            return true;
803        }
804
805        @Override
806        public final boolean isFloatingPoint() {
807            return true;
808        }
809
810        @Override
811        public final boolean isIeee754() {
812            return true;
813        }
814
815        @Override
816        public final boolean isIntegral() {
817            return false;
818        }
819
820        @Override
821        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
822            return this.ordinal() < prec.ordinal();
823        }
824
825        @Override
826        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
827            return prec.ordinal() < this.ordinal();
828        }
829
830        @Override
831        public final boolean isNumeric() {
832            return true;
833        }
834
835        @Override
836        public final boolean isSigned() {
837            return true;
838        }
839
840        @Override
841        public final boolean isUnlimited() {
842            return false;
843        }
844
845        @Override
846        public final NumericPrecision promote() {
847            return DOUBLE;
848        }
849
850        @Override
851        public final NumericPrecision promoteAgainst(
852            final NumericPrecision prec )
853        {
854            if (prec == LONG) return DOUBLE;
855            if (prec == UNLIMITED_INTEGER) return UNLIMITED_DECIMAL;
856            if ((prec == DOUBLE) || (prec == UNLIMITED_DECIMAL)) {
857                return prec;
858            }
859            return this;
860        }
861
862        @Override
863        public final NumericPrecision toFloatingPoint() {
864            return this;
865        }
866    },
867
868    /**
869     * IEEE <a href="http://en.wikipedia.org/wiki/Ieee_float">754-2008</a>
870     * single precision {@code float} value (32 bits). Though, strictly
871     * speaking, the value field size is actually smaller than that of a 64 bit
872     * {@link #LONG long} due to the {@code double}'s 53 bit <a
873     * href="http://en.wikipedia.org/wiki/Significand">significand</a> size,
874     * {@code double} is treated as a <i>more</i> precise value because of its
875     * significantly increased minimum-to-maximum value range.
876     */
877    DOUBLE( Double.class, double.class ) { /* 9 */
878        @Override
879        public final int compare( final NumericPrecision prec ) {
880            if (prec == this) {
881                return 0;
882            }
883            if (this.isLessPreciseThan(prec)) {
884                return -1;
885            }
886            return +1;
887        }
888
889        @Override
890        public final int size() {
891            return Double.SIZE;
892        }
893
894        @Override
895        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
896            return prec == this;
897        }
898
899        @Override
900        public final boolean isFinite() {
901            return true;
902        }
903
904        @Override
905        public final boolean isFloatingPoint() {
906            return true;
907        }
908
909        @Override
910        public final boolean isIeee754() {
911            return true;
912        }
913
914        @Override
915        public final boolean isIntegral() {
916            return false;
917        }
918
919        @Override
920        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
921            return this.ordinal() < prec.ordinal();
922        }
923
924        @Override
925        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
926            return prec.ordinal() < this.ordinal();
927        }
928
929        @Override
930        public final boolean isNumeric() {
931            return true;
932        }
933
934        @Override
935        public final boolean isSigned() {
936            return true;
937        }
938
939        @Override
940        public final boolean isUnlimited() {
941            return false;
942        }
943
944        @Override
945        public final NumericPrecision promote() {
946            return UNLIMITED_DECIMAL;
947        }
948
949        @Override
950        public final NumericPrecision promoteAgainst(
951            final NumericPrecision prec )
952        {
953            if (prec == UNLIMITED_INTEGER) return UNLIMITED_DECIMAL;
954            return prec == UNLIMITED_DECIMAL ? UNLIMITED_DECIMAL : this;
955        }
956
957        @Override
958        public final NumericPrecision toFloatingPoint() {
959            return this;
960        }
961    },
962
963    /**
964     * <b>Unlimited integer</b> value of arbitrary precision, which is only less
965     * precise than the unlimited {@link #UNLIMITED_DECIMAL decimal} precision
966     */
967    UNLIMITED_INTEGER( BigInteger.class, BigInteger.class ) { /* 10 */
968        @Override
969        public final int compare( final NumericPrecision prec ) {
970            if (prec == this) {
971                return 0;
972            }
973            if (this.isLessPreciseThan(prec)) {
974                return -1;
975            }
976            return +1;
977        }
978
979        @Override
980        public final int size() {
981            return -1;
982        }
983
984        @Override
985        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
986            return prec == this;
987        }
988
989        @Override
990        public final boolean isFinite() {
991            return false;
992        }
993
994        @Override
995        public final boolean isFloatingPoint() {
996            return false;
997        }
998
999        @Override
1000        public final boolean isIeee754() {
1001            return false;
1002        }
1003
1004        @Override
1005        public final boolean isIntegral() {
1006            return true;
1007        }
1008
1009        @Override
1010        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
1011            return prec == UNLIMITED_DECIMAL;
1012        }
1013
1014        @Override
1015        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
1016            if (prec == this) {
1017                return false;
1018            }
1019            if (prec == UNLIMITED_DECIMAL) {
1020                return false;
1021            }
1022            return true;
1023        }
1024
1025        @Override
1026        public final boolean isNumeric() {
1027            return true;
1028        }
1029
1030        @Override
1031        public final boolean isSigned() {
1032            return true;
1033        }
1034
1035        @Override
1036        public final boolean isUnlimited() {
1037            return true;
1038        }
1039
1040        @Override
1041        public final NumericPrecision promote() {
1042            return UNLIMITED_DECIMAL;
1043        }
1044
1045        @Override
1046        public final NumericPrecision promoteAgainst(
1047            final NumericPrecision prec )
1048        {
1049            return prec.isFloatingPoint() ? UNLIMITED_DECIMAL : this;
1050        }
1051
1052        @Override
1053        public final NumericPrecision toFloatingPoint() {
1054            return UNLIMITED_DECIMAL;
1055        }
1056    },
1057
1058    /**
1059     * <b>Unlimited decimal</b> value of arbitrary precision and the highest
1060     * precision of any specifiable value
1061     */
1062    UNLIMITED_DECIMAL( BigDecimal.class, BigDecimal.class ) { /* 11 */
1063        @Override
1064        public final int compare( final NumericPrecision prec ) {
1065            if (prec == this) {
1066                return 0;
1067            }
1068            return +1;
1069        }
1070
1071        @Override
1072        public final int size() {
1073            return -1;
1074        }
1075
1076        @Override
1077        public final boolean isEquallyPreciseAs( final NumericPrecision prec ) {
1078            return prec == this;
1079        }
1080
1081        @Override
1082        public final boolean isFinite() {
1083            return false;
1084        }
1085
1086        @Override
1087        public final boolean isFloatingPoint() {
1088            return true;
1089        }
1090
1091        @Override
1092        public final boolean isIeee754() {
1093            return false;
1094        }
1095
1096        @Override
1097        public final boolean isIntegral() {
1098            return false;
1099        }
1100
1101        @Override
1102        public final boolean isLessPreciseThan( final NumericPrecision prec ) {
1103            return false;
1104        }
1105
1106        @Override
1107        public final boolean isMorePreciseThan( final NumericPrecision prec ) {
1108            return prec != this;
1109        }
1110
1111        @Override
1112        public final boolean isNumeric() {
1113            return true;
1114        }
1115
1116        @Override
1117        public final boolean isSigned() {
1118            return true;
1119        }
1120
1121        @Override
1122        public final boolean isUnlimited() {
1123            return true;
1124        }
1125
1126        @Override
1127        public final NumericPrecision promote() {
1128            return this;
1129        }
1130
1131        @Override
1132        public final NumericPrecision promoteAgainst(
1133            final NumericPrecision prec )
1134        {
1135            return this;
1136        }
1137
1138        @Override
1139        public final NumericPrecision toFloatingPoint() {
1140            return this;
1141        }
1142    },
1143
1144    ;
1145
1146    private final static Map<Class<?>,NumericPrecision> _theClassPrecisionMap = new IdentityHashMap<Class<?>,NumericPrecision>();
1147
1148    public static NumericPrecision MAXIMUM = UNLIMITED_DECIMAL;
1149    public static NumericPrecision MINIMUM = UNKNOWN;
1150
1151    static {
1152        for (final NumericPrecision prec : NumericPrecision.values()) {
1153            _theClassPrecisionMap.put(prec.getNumberClass(), prec);
1154            _theClassPrecisionMap.put(prec.getPrimitiveClass(), prec);
1155        }
1156        _theClassPrecisionMap.put(null, NULL);
1157        _theClassPrecisionMap.put(AtomicBoolean.class, BIT);
1158        _theClassPrecisionMap.put(AtomicInteger.class, INTEGER);
1159        _theClassPrecisionMap.put(AtomicLong.class, LONG);
1160        _theClassPrecisionMap.put(Appendable.class, UNKNOWN);
1161        _theClassPrecisionMap.put(StringBuilder.class, UNKNOWN);
1162        _theClassPrecisionMap.put(StringBuffer.class, UNKNOWN);
1163        _theClassPrecisionMap.put(CharSequence.class, UNKNOWN);
1164    }
1165
1166    private final Class<?> _theNumberClass;
1167    private final Class<?> _thePrimitiveClass;
1168
1169    private NumericPrecision(
1170        final Class<?> aNumberClass,
1171        final Class<?> aPrimitiveClass )
1172    {
1173        this._theNumberClass = aNumberClass;
1174        this._thePrimitiveClass = aPrimitiveClass;
1175    }
1176
1177    /**
1178     * {@link Comparable#compareTo(Object) Primitive1} this precision against
1179     * another. This method is included, and named what it is because
1180     * {@link Enum} implements {@code compareTo} to simply compare the
1181     * {@link Enum#ordinal() ordinal} values of any two compatible enumerations.
1182     *
1183     * @param prec
1184     *        another precision
1185     * @return 0 if this precision and the specified one are the same precision,
1186     *         -1 if this precision is less precise, or +1 if this precision is
1187     *         more precise
1188     * @see Comparable#compareTo(Object)
1189     */
1190    public abstract int compare( final NumericPrecision prec );
1191
1192    public final Class<?> getNumberClass() {
1193        return this._theNumberClass;
1194    }
1195
1196    public final Class<?> getPrimitiveClass() {
1197        return this._thePrimitiveClass;
1198    }
1199
1200    /**
1201     * @param prec
1202     *        another precision enumeration
1203     * @return {@code true} if this precision is as precise as the specified
1204     *         precision
1205     */
1206    public abstract boolean isEquallyPreciseAs( NumericPrecision prec );
1207
1208    /**
1209     * @return {@code true} if this precision is known and finite
1210     */
1211    public abstract boolean isFinite();
1212
1213    /**
1214     * @return {@code true} if this precision represents a floating point value
1215     */
1216    public abstract boolean isFloatingPoint();
1217
1218    /**
1219     * @return {@code true} if this precision represents an IEEE 754 floating
1220     *         point value
1221     * @see <a href="http://en.wikipedia.org/wiki/IEEE_754">IEEE 754</a>
1222     *      (Wikipedia)
1223     */
1224    public abstract boolean isIeee754();
1225
1226    /**
1227     * @return {@code true} if this precision represents an integral (no decimal
1228     *         point) value
1229     */
1230    public abstract boolean isIntegral();
1231
1232    /**
1233     * @param prec
1234     *        another precision enumeration
1235     * @return {@code true} if this precision is less precise or as equally
1236     *         precise as the specified precision
1237     */
1238    public final boolean isLessOrEquallyPreciseAs( final NumericPrecision prec )
1239    {
1240        if (this.isEquallyPreciseAs(prec)) {
1241            return true;
1242        }
1243        if (this.isLessPreciseThan(prec)) {
1244            return true;
1245        }
1246        return false;
1247    }
1248
1249    /**
1250     * @param prec
1251     *        another precision enumeration
1252     * @return {@code true} if this precision is less precise than the specified
1253     *         precision
1254     */
1255    public abstract boolean isLessPreciseThan( NumericPrecision prec );
1256
1257    /**
1258     * @param prec
1259     *        another precision enumeration
1260     * @return {@code true} if this precision is more precise or as equally
1261     *         precise as the specified precision
1262     */
1263    public final boolean isMoreOrEquallyPreciseAs( final NumericPrecision prec )
1264    {
1265        if (this.isEquallyPreciseAs(prec)) {
1266            return true;
1267        }
1268        if (this.isMorePreciseThan(prec)) {
1269            return true;
1270        }
1271        return false;
1272    }
1273
1274    /**
1275     * @param prec
1276     *        another precision enumeration
1277     * @return {@code true} if this precision is more precise than the specified
1278     *         precision
1279     */
1280    public abstract boolean isMorePreciseThan( final NumericPrecision prec );
1281
1282    /**
1283     * @return {@code true} if this is a valid numeric precision
1284     */
1285    public abstract boolean isNumeric();
1286
1287    /**
1288     * @return {@code true} if this precision is known and signed
1289     */
1290    public abstract boolean isSigned();
1291
1292    /**
1293     * @return {@code true} if objects with this precision are implemented using
1294     *         unlimited precision (e.g., {@link BigInteger} or
1295     *         {@link BigDecimal})
1296     */
1297    public abstract boolean isUnlimited();
1298
1299    public final NumericPrecision maximumOf( final NumericPrecision prec ) {
1300        if (this.isMoreOrEquallyPreciseAs(prec)) {
1301            return this;
1302        }
1303        return prec;
1304    }
1305
1306    public final NumericPrecision maximumOfAll(
1307        final NumericPrecision... precisions )
1308    {
1309        NumericPrecision max = this;
1310        for (final NumericPrecision prec : precisions) {
1311            max = max.maximumOf(prec);
1312        }
1313        return max;
1314    }
1315
1316    /**
1317     * @return a minimally more, or the "next" more, numerically precise
1318     *         enumeration value
1319     */
1320    public abstract NumericPrecision promote();
1321
1322    /**
1323     * Answer a precision value such that any mathematical operation between
1324     * values of this precision and those of the specified one will not result
1325     * in a loss of information. The dynamics of this promotion are such that
1326     * all primitive promotions will rapidly converge upon {@link #DOUBLE}
1327     * unless precisions smaller than {@link #LONG} are explicitly promoted
1328     * against {@link #FLOAT}. {@link #isIntegral() Integral} numbers are always
1329     * promoted to floating points (rational real numbers when compared against
1330     * them. The {@link #isUnlimited() unlimited} precision types (e.g.,
1331     * {@link BigInteger} and {@link BigDecimal}) will always force a promotion
1332     * to themselves.<br>
1333     * <br>
1334     * Note that this algorithm may not be recommended under all circumstances,
1335     * for instance under division where it may be desirable to promote to a
1336     * floating point precision under all circumstances. Therefore treat this
1337     * promotion behavior as a default behavior which remains agnostic to
1338     * specific operations.
1339     *
1340     * @param prec
1341     *        a precision to test against
1342     * @return a precision such that any mathematical operation between values
1343     *         of this precision and those of the specified one will not result
1344     *         in a loss of information
1345     */
1346    public abstract NumericPrecision promoteAgainst( final NumericPrecision prec );
1347
1348    /**
1349     * @return the number of bits used to represent values of this type in this
1350     *         system or -1 for {@link #UNKNOWN} or {@link #isUnlimited()
1351     *         unlimited}
1352     */
1353    public abstract int size();
1354
1355    /**
1356     * @return a minimally more, or the "next" more, precise <i>floating
1357     *         point</i> enumeration value if this was integral or otherwise
1358     *         answer itself
1359     */
1360    public abstract NumericPrecision toFloatingPoint();
1361
1362    public final static NumericPrecision getPrecisionFor( final Class<?> aClass )
1363    {
1364        final NumericPrecision prec = _theClassPrecisionMap.get(aClass);
1365        if ( prec == null ) {
1366            return UNKNOWN;
1367        }
1368        return prec;
1369    }
1370
1371    public final static NumericPrecision getPrecisionFor( final Object aValue )
1372    {
1373        final Class<?> aClass = aValue.getClass();
1374        final NumericPrecision prec = _theClassPrecisionMap.get(aClass);
1375        if (prec != null) {
1376            return prec;
1377        }
1378        if (aValue instanceof SealedScalarDomain) {
1379            final SealedScalarDomain aDomain = (SealedScalarDomain)aValue;
1380            return aDomain.getPrecision();
1381        }
1382        return UNKNOWN;
1383    }
1384}