001/* The overflow strategy classes.
002
003 Copyright (c) 2002-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.math;
029
030import java.math.BigInteger;
031import java.util.HashMap;
032import java.util.Iterator;
033import java.util.Map;
034
035///////////////////////////////////////////////////////////////////
036//// Overflow
037
038/**
039 The Overflow class provides a type safe enumeration of strategies for
040 handling numeric overflows for FixPoint data types.
041 Overflows are typically resolved after performing a FixPoint
042 arithmetic operation or transformation.
043 <p>
044 The active class functionality is provided by the
045 {@link #quantize(BigInteger, Precision) quantize} method. This method
046 evaluates an unscaled {@link BigInteger BigInteger} value and a
047 Precision constraint and creates a FixPoint object with a new
048 unscaled value and precision that conforms to the corresponding
049 overflow strategy. Depending on the overflow strategy used,
050 the unscaled integer value or the precision may be changed as
051 part of the overflow process.
052 <p>
053 The overflow strategies supported are as follows:
054 <ul>
055
056 <li> <i><b>grow</b></i> <br>
057 If the integer value does not fall within the dynamic range
058 of the Precision constraint, increase the Precision to the
059 minimum dynamic range needed to include the integerValue.
060 Note that the actual integer unscaled value will not change
061 during this overflow strategy.
062 This rounding mode is supported by the static
063 {@link #quantizeGrow(BigInteger, Precision) quantizeGrow} method
064 and the Overflow singletons {@link #GROW} and {@link #GENERAL}.
065
066 <li> <i><b>minimize</b></i> <br>
067 Represent the unscaled integer value with the minimum
068 number of data bits. The sign and exponent of the
069 new precision constraint is determined by the Precision
070 parameter. The use of this overflow strategy may increase
071 or decrease the Precision of the value.
072 Note that the actual integer unscaled value will not change
073 during this overflow strategy.
074 This rounding mode is supported by the static
075 {@link #quantizeMinimum(BigInteger, Precision) quantizeMinimize}
076 method and the Overflow singleton {@link #MINIMIZE} .
077
078 <li> <i><b>modulo</b></i> <br>
079 This overflow strategy will perform a twos complement modulo
080 operation any integer values that are outside of the
081 dynamic range of the Precision constraint.
082 Note that the actual precision will not change
083 during this overflow strategy.
084 This rounding mode is supported by the static
085 {@link #quantizeModulo(BigInteger, Precision) quantizeModulo}
086 method and the Overflow singletons {@link #MODULO} and {@link #WRAP}.
087
088 <li> <i><b>saturate</b></i> <br>
089 If the integer value falls outside of the Precision dynamic
090 range, this overflow strategy will saturate result.
091 If the value is below the minimum of the range, the
092 minimum value of the range is used. If the value is above
093 the maximum of the range, the maximum value of the range
094 is used.
095 Note that the precision will not change during this overflow strategy.
096 This rounding mode is supported by the static
097 {@link #quantizeSaturate(BigInteger, Precision) quantizeSaturate}
098 method and the Overflow singletons {@link #SATURATE} and
099 {@link #CLIP}.
100
101 <li> <i><b>to_zero</b></i> <br>
102 If the integer value falls outside of the Precision dynamic
103 range, this overflow strategy will set the integer value to zero.
104 Note that the actual precision will not change
105 during this overflow strategy.
106 This rounding mode is supported by the static
107 {@link #quantizeToZero(BigInteger, Precision) quantizeToZero}
108 method and the Overflow singleton {@link #TO_ZERO}.
109
110 <li> <i><b>trap</b></i> <br>
111 If the integer value falls outside of the Precision dynamic
112 range, a {@link java.lang.ArithmeticException} is generated.
113 This rounding mode is supported by the
114 singleton {@link #TRAP}.
115 </ul>
116
117 <p>
118 A specific strategy may be chosen dynamically by invoking
119 {@link #forName forName} or {@link #getName getName}
120 with one of the above strategy names. Alternatively a strategy
121 may be selected by using one of the static singletons.
122 <p>
123 Division by zero can trigger the use of the plusInfinity or minusInfinity
124 methods, which return null, except in the case of the <i>to_zero</i>
125 and <i>saturate</i> strategies for which infinity is well-defined.
126
127 @author Ed Willink
128 @version $Id$
129 @since Ptolemy II 2.1
130 @Pt.ProposedRating Red (Ed.Willink)
131 @Pt.AcceptedRating Red
132 @see ptolemy.math.FixPoint
133 @see ptolemy.math.Quantization
134 @see ptolemy.math.Rounding
135 */
136public abstract class Overflow implements Cloneable {
137
138    ///////////////////////////////////////////////////////////////////
139    ////                         public methods                    ////
140
141    /** Return this, that is, return the reference to this object.
142     *  @return This Overflow.
143     */
144    @Override
145    public Object clone() {
146        return this;
147    }
148
149    /** Determine if the argument represents the same Overflow as this
150     *  object.
151     *  @param object Another object.
152     *  @return True if the argument represents the same Overflow as
153     *   this object; false otherwise.
154     */
155    @Override
156    public boolean equals(Object object) {
157        // since Overflow is a type safe enumeration, can use == to
158        // test equality.
159        return this == object;
160    }
161
162    /** Return an instance of this class with the specified name.
163     *
164     *  @param name The name of the Overflow strategy to find.
165     *  @return An instance of Overflow or null.
166     */
167    public static Overflow forName(String name) {
168        return (Overflow) _nameToOverflow.get(name);
169    }
170
171    /** Return an instance of this class with the specified name,
172     *  or null if none exists.
173     *
174     *  @param name The name of the Overflow strategy to find.
175     *  @return An instance of Overflow.
176     *  @exception IllegalArgumentException If the string does not
177     *   match one of the known strategies.
178     */
179    public static Overflow getName(String name)
180            throws IllegalArgumentException {
181        Overflow overflow = (Overflow) _nameToOverflow.get(name);
182
183        if (overflow != null) {
184            return overflow;
185        }
186
187        throw new IllegalArgumentException(
188                "Unknown overflow strategy \"" + name + "\".");
189    }
190
191    /** Return a hash code value for this object.
192     */
193    @Override
194    public int hashCode() {
195        return _name.hashCode();
196    }
197
198    /**
199     * Determines whether the given BigInteger unscaled value is considered
200     * an "underflow" or an "overflow" under the given Precision constraint.
201     * This will occur if the value is less than the minimum unscaled value of
202     * the given Precision constraint or more than the maximum unscaled value
203     * of the given Precision constraint.
204     *
205     * @param bigInt The value to test for underflow.
206     * @param precision The Precision constraint to use for the test.
207     * @return true if the value is considered an "underflow" or "overflow,
208     * false otherwise.
209     */
210    public static boolean isOutOfRange(BigInteger bigInt, Precision precision) {
211        if (bigInt.compareTo(precision.getMaximumUnscaledValue()) > 0
212                || bigInt.compareTo(precision.getMinimumUnscaledValue()) < 0) {
213            return true;
214        }
215        return false;
216    }
217
218    /**
219     * Determines whether the given BigInteger unscaled value is considered
220     * an "overflow" under the given Precision constraint. This will occur
221     * if the value is larger than the maximum unscaled value of
222     * the given Precision constraint.
223     * (@see Precision#getMaximumUnscaledValue())
224     *
225     * @param value The value to test for overflow.
226     * @param precision The Precision constraint to use for the test.
227     * @return true if the value is considered an "overflow", false if
228     * it is not an "overflow".
229     */
230    public static boolean isOverflow(BigInteger value, Precision precision) {
231        if (value.compareTo(precision.getMaximumUnscaledValue()) > 0) {
232            return true;
233        }
234        return false;
235    }
236
237    /**
238     * Determines whether the given BigInteger unscaled value is considered
239     * an "underflow" under the given Precision constraint. This will occur
240     * if the value is less than the minimum unscaled value of
241     * the given Precision constraint.
242     * (@see Precision#getMinimumUnscaledValue())
243     *
244     * @param bigInt The value to test for underflow.
245     * @param precision The Precision constraint to use for the test.
246     * @return true if the value is considered an "underflow", false if
247     * it is not an "underflow".
248     */
249    public static boolean isUnderflow(BigInteger bigInt, Precision precision) {
250        if (bigInt.compareTo(precision.getMinimumUnscaledValue()) < 0) {
251            return true;
252        }
253        return false;
254    }
255
256    /**
257     * Return an iterator for the names of all overflow types.
258     * @return An iterator for the names of all overflow types.
259     */
260    public static Iterator nameIterator() {
261        return _nameToOverflow.keySet().iterator();
262    }
263
264    /** Return the value of minus infinity, or null if unrepresentable.
265     *  <p>
266     *  The saturation value is returned for the <i>saturate</i> and
267     *  <i>to_zero</i> strategies for which infinity is quantizable.
268     *  Null is returned for other strategies.
269     *
270     *  @param quant The quantization specification.
271     *  @return The value if defined, null if not..
272     */
273    public BigInteger minusInfinity(Quantization quant) {
274        return null;
275    }
276
277    /** Return the value of plus infinity, or null if unrepresentable.
278     *  <p>
279     *  The saturation value is returned for the <i>saturate</i> and
280     *  <i>to_zero</i> strategies for which infinity is quantizable.
281     *  Null is returned for other strategies.
282     *  @param quant The quantization specification.
283     *  @return The value if defined, null if not.
284     */
285    public BigInteger plusInfinity(Quantization quant) {
286        return null;
287    }
288
289    /** Return a new FixPoint object based on the given BigInteger
290     *  value and Precision constraint. This method will return
291     *  a valid FixPoint object that conforms to the given
292     *  overflow strategy implemented by the extending class.
293     *
294     *  @param integerValue The unbounded integer value.
295     *  @param precision The Precision constraint of the quantization.
296     *  @return A valid FixPoint value that conforms to the overflow
297     *  strategy.
298     */
299    abstract public FixPoint quantize(BigInteger integerValue,
300            Precision precision);
301
302    /**
303     * Quantize a FixPoint value using a "grow" overflow strategy.
304     * If the Precision format does not provide sufficient dynamic range
305     * for the value, increase the Precision to the minimum dynamic range
306     * needed to include the integerValue. Note that the actual
307     * integer unscaled value will not change during this overflow
308     * strategy.
309     *
310     * @param integerValue unscaled integer value to check for overflow
311     * @param precision the precision constraint used for the overflow check
312     * @return Valid FixPoint data object
313     */
314    public static FixPoint quantizeGrow(BigInteger integerValue,
315            Precision precision) {
316        if (isOutOfRange(integerValue, precision)) {
317            return quantizeMinimum(integerValue, precision);
318        }
319        return new FixPoint(integerValue, precision);
320    }
321
322    /**
323     * Generates a new FixPoint data value based on the unscaled
324     * value bigInt using as few bits as possible. The sign and
325     * exponent of the precision are obtained from the Precision
326     * parameter.
327     *
328     * @param bigInt Unscaled value to use for the FixPoint result
329     * @param p Used to obtain the sign and exponent of the new FixPoint value.
330     * @return FixPoint value with as few bits as necessary.
331     */
332    public static FixPoint quantizeMinimum(BigInteger bigInt, Precision p) {
333        int sign = p.isSigned() ? 1 : 0;
334        int int_bits = bigInt.bitLength();
335        if (int_bits == 0) {
336            int_bits++;
337        }
338        int new_bits = int_bits + sign;
339
340        Precision newPrecision = new Precision(sign, new_bits, p.getExponent());
341        return new FixPoint(bigInt, newPrecision);
342
343    }
344
345    /**
346     * Quantize a FixPoint value using a "modulo" overflow strategy.
347     * If the unscaled integer value is outside of the dynamic range
348     * provided by the Precision constraint, modify the integer
349     * value to fit within the dynamic range using a
350     * modulo operation. Note that the Precision of the FixPoint
351     * value remains the same.
352     *
353     * @param integerValue unscaled integer value to check for overflow
354     * @param precision the precision constraint used for the overflow check
355     * @return Valid FixPoint data object
356     */
357    public static FixPoint quantizeModulo(BigInteger integerValue,
358            Precision precision) {
359        if (!isOutOfRange(integerValue, precision)) {
360            return new FixPoint(integerValue, precision);
361        }
362
363        BigInteger moduloInteger = null;
364
365        if (!precision.isSigned()) {
366            // If the precision is unsigned, the BigInteger will
367            // be positive and the "modulo" value is the
368            // remainder of "integerValue divided by # of levels".
369            moduloInteger = integerValue
370                    .remainder(precision.getNumberOfLevels());
371        } else {
372            // If the precision is signed, we need to perform a
373            // twos complement modulo.
374
375            BigInteger minValue = precision.getMinimumUnscaledValue();
376            moduloInteger = integerValue.subtract(minValue);
377
378            BigInteger modValue = precision.getNumberOfLevels();
379            moduloInteger = moduloInteger.remainder(modValue);
380
381            if (integerValue.signum() < 0) {
382                moduloInteger = moduloInteger.add(modValue);
383            }
384            moduloInteger = moduloInteger.add(minValue);
385        }
386
387        return new FixPoint(moduloInteger, precision);
388    }
389
390    /**
391     * Quantize a FixPoint value using a "saturate" overflow strategy.
392     * If the unscaled integer value is outside of the dynamic range
393     * provided by the Precision constraint, modify the integer
394     * value to fit within the dynamic range by saturating the
395     * value to the maximum or minimum value supported by the
396     * Precision constraint. Note that the Precision of the FixPoint
397     * value remains the same.
398     *
399     * @param integerValue unscaled integer value to check for overflow
400     * @param precision the precision constraint used for the overflow check
401     * @return Valid FixPoint data object
402     */
403    public static FixPoint quantizeSaturate(BigInteger integerValue,
404            Precision precision) {
405        if (isUnderflow(integerValue, precision)) {
406            return new FixPoint(precision.getMinimumUnscaledValue(), precision);
407        }
408        if (isOverflow(integerValue, precision)) {
409            return new FixPoint(precision.getMaximumUnscaledValue(), precision);
410        }
411        return new FixPoint(integerValue, precision);
412    }
413
414    /**
415     * Quantize a FixPoint value using a "to Zero" overflow strategy.
416     * If the unscaled integer value is outside of the dynamic range
417     * provided by the Precision constraint, set the integer
418     * value to zero. Note that the Precision of the FixPoint
419     * value remains the same.
420     *
421     * @param integerValue unscaled integer value to check for overflow
422     * @param precision the precision constraint used for the overflow check
423     * @return Valid FixPoint data object
424     */
425    public static FixPoint quantizeToZero(BigInteger integerValue,
426            Precision precision) {
427        if (isOutOfRange(integerValue, precision)) {
428            return new FixPoint(BigInteger.ZERO, precision);
429        }
430        return new FixPoint(integerValue, precision);
431    }
432
433    /** Return the string representation of this overflow.
434     *  @return A String.
435     */
436    @Override
437    public String toString() {
438        return _name;
439    }
440
441    ///////////////////////////////////////////////////////////////////
442    ////                         public variables                  ////
443    // NOTE: It may seem strange that these inner classes are built this
444    // way instead of as anonymous classes...  This code was copied from
445    // ptolemy.data.type.BaseType where an explanation that was valid
446    // for that usage may be found.
447
448    /** Singleton implementing Grow overflow strategy. */
449    public static final Grow GROW = new Grow();
450
451    /** Singleton implementing Modulo overflow strategy. */
452    public static final Modulo MODULO = new Modulo();
453
454    /** Singleton implementing Minimize overflow strategy. */
455    public static final Minimize MINIMIZE = new Minimize();
456
457    /** Singleton implementing Trap overflow strategy. */
458    public static final Trap TRAP = new Trap();
459
460    /** Singleton implementing Saturate overflow strategy. */
461    public static final Saturate SATURATE = new Saturate();
462
463    /** Singleton implementing to zero overflow strategy. */
464    public static final ToZero TO_ZERO = new ToZero();
465
466    // The following singleton classes are listed below (and out of
467    // alphabetic order) because they depend on the construction of
468    // other singleton objects before they can be defined.
469
470    /** Singleton implementing Saturate overflow strategy. */
471    public static final Saturate CLIP = SATURATE;
472
473    /** Singleton implementing Grow overflow strategy. */
474    public static final Grow GENERAL = GROW;
475
476    /** Singleton implementing Modulo overflow strategy. */
477    public static final Modulo WRAP = MODULO;
478
479    /** Singleton implementing Trap overflow strategy. */
480    public static final Trap THROW = TRAP;
481
482    /** The grow overflow strategy. Allow growth of value. */
483    public static class Grow extends Overflow {
484        private Grow() {
485            super("grow");
486        }
487
488        @Override
489        public FixPoint quantize(BigInteger integerValue, Precision precision) {
490            return quantizeGrow(integerValue, precision);
491        }
492
493    }
494
495    /** The minimize overflow strategy. */
496    public static class Minimize extends Overflow {
497        private Minimize() {
498            super("minimize");
499            _addOverflow(this, "shrink");
500        }
501
502        @Override
503        public FixPoint quantize(BigInteger integerValue, Precision precision) {
504            return quantizeMinimum(integerValue, precision);
505        }
506
507    }
508
509    /** The modulo overflow strategy. */
510    public static class Modulo extends Overflow {
511        private Modulo() {
512            super("modulo");
513            _addOverflow(this, "wrap");
514        }
515
516        @Override
517        public FixPoint quantize(BigInteger integerValue, Precision precision) {
518            return quantizeModulo(integerValue, precision);
519        }
520
521    }
522
523    /** The saturate overflows strategy. */
524    public static class Saturate extends Overflow {
525        private Saturate() {
526            super("saturate");
527            _addOverflow(this, "clip");
528        }
529
530        @Override
531        public BigInteger minusInfinity(Quantization quant) {
532            return quant.getMinimumUnscaledValue();
533        }
534
535        @Override
536        public BigInteger plusInfinity(Quantization quant) {
537            return quant.getMaximumUnscaledValue();
538        }
539
540        @Override
541        public FixPoint quantize(BigInteger integerValue, Precision precision) {
542            return quantizeSaturate(integerValue, precision);
543        }
544    }
545
546    /** The overflow to zero strategy. */
547    public static class ToZero extends Overflow {
548        private ToZero() {
549            super("to_zero");
550            _addOverflow(this, "overflow_to_zero"); // For compatibility.
551        }
552
553        @Override
554        public BigInteger minusInfinity(Quantization quant) {
555            return BigInteger.ZERO;
556        }
557
558        @Override
559        public BigInteger plusInfinity(Quantization quant) {
560            return BigInteger.ZERO;
561        }
562
563        @Override
564        public FixPoint quantize(BigInteger integerValue, Precision precision) {
565            return quantizeToZero(integerValue, precision);
566        }
567    }
568
569    /** The trap overflows strategy. */
570    public static class Trap extends Overflow {
571        private Trap() {
572            super("trap");
573            _addOverflow(this, "throw");
574        }
575
576        @Override
577        public FixPoint quantize(BigInteger integerValue, Precision precision) {
578            if (isUnderflow(integerValue, precision)) {
579                throw new ArithmeticException("Minimum overflow threshold of "
580                        + precision.getMinimumUnscaledValue()
581                        + " exceeded with value " + integerValue);
582            }
583            if (isOverflow(integerValue, precision)) {
584                throw new ArithmeticException("Maximum overflow threshold of "
585                        + precision.getMaximumUnscaledValue()
586                        + " exceeded with value " + integerValue);
587            }
588            return new FixPoint(integerValue, precision);
589        }
590    }
591
592    ///////////////////////////////////////////////////////////////////
593    ////                     protected constructor                 ////
594
595    /** Construct an Overflow object with the given String name.
596     *  This name is used for finding an Overflow object at a later
597     *  time (@see #forName(String)). This constructor
598     *  is protected to make a type safe enumeration.
599     *
600     * @param name The String name to give this Overflow strategy.
601     *
602     */
603    protected Overflow(String name) {
604        _name = name;
605        _addOverflow(this, name);
606    }
607
608    // The constructor is protected to make a type safe enumeration.
609
610    ///////////////////////////////////////////////////////////////////
611    ////                    package private method                 ////
612    // Add entries in this class to index the given name to
613    // the given overflow type.
614    static void _addOverflow(Overflow type, String name) {
615        // Because the private variables are below the public variables
616        // that call this initializer,
617        // it doesn't work to initialize this statically.
618        if (_nameToOverflow == null) {
619            _nameToOverflow = new HashMap();
620        }
621
622        _nameToOverflow.put(name, type);
623    }
624
625    ///////////////////////////////////////////////////////////////////
626    ////                         private variables                 ////
627    private String _name;
628
629    // A map from overflow type name to the overflow type for all
630    //  overflow types.
631    private static volatile Map _nameToOverflow;
632
633}