001/** A class defining quantization to a FixPoint number.
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
028 */
029package ptolemy.math;
030
031import java.util.StringTokenizer;
032
033/**
034 The FixPointQuantization class defines the mapping of numeric values
035 with unlimited precision to the finite precision supported by arithmetic
036 using the FixPoint class.
037 <p>
038 It comprises a
039 <ul>
040 <li>
041 <b>Precision</b>: to define the accuracy of the finite precision numbers.
042 <li>
043 <b>Overflow</b>: to define the treatment of out-of-range numbers.
044 <li>
045 <b>Rounding</b>: to define the loss of precision for in-range numbers.
046 </ul>
047 The active class functionality is provided by the quantize method, which
048 is normally invoked from FixPoint.quantize to enforce quantization
049 constraints upon the result of an unconstrained computation.
050 <p>
051 An instance of the class is immutable, meaning
052 that its value is set in the constructor and cannot then be modified.
053
054 @author Ed Willink
055 @version $Id$
056 @since Ptolemy II 2.1
057 @Pt.ProposedRating Red (Ed.Willink)
058 @Pt.AcceptedRating Red
059 @see ptolemy.math.FixPoint
060 @see ptolemy.math.Precision
061 @see ptolemy.math.Overflow
062 @see ptolemy.math.Rounding
063 */
064public class FixPointQuantization extends Quantization {
065    /** Construct a FixPointQuantization object based on the provided
066     *  string.  The string may consist of just <i>precision</i> or
067     *  <i>precision, overflow</i> or
068     *  <i>precision, overflow, rounding</i>, and may optionally be
069     *  enclosed in parentheses.
070     *
071     *  <p> <i>precision</i> must be one of the Precision formats;
072     *  <i>integer-bits.fraction-bits</i> or
073     *  <i>total-bits/integer-bits</i>.
074     *
075     *  <p> <i>overflow</i> must be
076     *  one of the Overflow strategies; e.g.  <i>saturate</i> or
077     *  <i>modulo</i> or <i>trap</i>.   The default is <i>saturate</i>.
078     *
079     *  <p> <i>rounding</i> must be one
080     *  of the Rounding strategies; e.g.  <i>up</i> or <i>half_even</i>
081     *  or <i>unnecessary</i>.   The default is <i>nearest</i>.
082     *
083     *
084     *  @param string The string representing the
085     *  quantization specification.
086     *  @exception IllegalArgumentException If the precision string
087     *   supplied, overflow strategy or rounding strategy does not
088     *   match one of the known formats.
089     */
090    public FixPointQuantization(String string) throws IllegalArgumentException {
091        super(Overflow.SATURATE, Rounding.NEAREST);
092
093        int strLen = string.length();
094
095        if (strLen >= 2 && string.charAt(0) == '('
096                && string.charAt(strLen - 1) == ')') {
097            string = string.substring(1, strLen - 1);
098        }
099
100        StringTokenizer st = new StringTokenizer(string, ",");
101
102        if (!st.hasMoreTokens()) {
103            throw new IllegalArgumentException("A precision string"
104                    + " consisting of two integers separated "
105                    + " by a '/', or '.' token is required");
106        }
107
108        _precision = new Precision(st.nextToken());
109
110        if (st.hasMoreTokens()) {
111            _overflow = Overflow.getName(st.nextToken());
112        }
113
114        if (st.hasMoreTokens()) {
115            _rounding = Rounding.getName(st.nextToken());
116        }
117
118        if (st.hasMoreTokens()) {
119            throw new IllegalArgumentException("FixPointQuantization "
120                    + "requires at most a precision overflow and rounding,");
121        }
122    }
123
124    /** Construct a FixPointQuantization with specified precision, overflow
125     *  and rounding.
126     *
127     *  @param precision The precision.
128     *  @param overflow The overflow.
129     *  @param rounding The rounding.
130     */
131    public FixPointQuantization(Precision precision, Overflow overflow,
132            Rounding rounding) {
133        super(overflow, rounding);
134        _precision = precision;
135    }
136
137    ///////////////////////////////////////////////////////////////////
138    ////                         public methods                    ////
139
140    /** Return true if the given object describes the same
141     *  mapping to quantized values as this object.
142     *
143     *  @param object The FixPointQuantization object to use for equality
144     *  checking.
145     *  @return True if the quantizations are equal.
146     */
147    @Override
148    public boolean equals(Object object) {
149        if (super.equals(object) && object instanceof FixPointQuantization) {
150            FixPointQuantization other = (FixPointQuantization) object;
151
152            if (_precision.equals(other._precision)) {
153                return true;
154            }
155        }
156
157        return false;
158    }
159
160    /** Return the precision of the mantissa of the value.
161     *  @return The precision.
162     */
163    @Override
164    public Precision getMantissaPrecision() {
165        return _precision;
166    }
167
168    /**
169     * Return the precision.
170     *
171     * @see #setPrecision(Precision)
172     * @return Precision object.
173     */
174    @Override
175    public Precision getPrecision() {
176        return _precision;
177    }
178
179    /** Return a hash code value for this FixPointQuantization. This
180     *  method returns the bitwise xor of the hashcode of the
181     *  superclass (Quantization) and the hashcode of the precision.
182     *  @return A hash code value for this Quantization.
183     */
184    @Override
185    public int hashCode() {
186        return super.hashCode() >>> _precision.hashCode();
187    }
188
189    /** Return a FixPointQuantization with a changed overflow strategy.
190     *  @param overflow The new overflow strategy.
191     *  @return A new quantization.
192     */
193    public FixPointQuantization setOverflow(Overflow overflow) {
194        return new FixPointQuantization(_precision, overflow, getRounding());
195    }
196
197    /** Return a FixPointQuantization with a changed precision.
198     *
199     *  @see #getPrecision()
200     *  @param precision The new precision.
201     *  @return A new quantization.
202     */
203    public FixPointQuantization setPrecision(Precision precision) {
204        return new FixPointQuantization(precision, getOverflow(),
205                getRounding());
206    }
207
208    /** Return a FixPointQuantization with a changed rounding strategy.
209     *  @param rounding The new rounding.strategy.
210     *  @return A new quantization.
211     */
212    public FixPointQuantization setRounding(Rounding rounding) {
213        return new FixPointQuantization(_precision, getOverflow(), rounding);
214    }
215
216    /** Return a string representing this quantization. The string is
217     *  expressed as "(<i>m.n, o, p</i>)", where <i>m</i>
218     *  indicates the number of integer bits, <i>n</i> represents
219     *  the number of fractional bits and <i>o</i> represents
220     *  the overflow strategy and <i>r</i> represents
221     *  the rounding strategy.
222     *  @return A string representing this quantization.
223     */
224    @Override
225    public String toString() {
226        // TODO: check for null precision
227        return "(" + _precision.getIntegerBitLength() + "."
228                + _precision.getFractionBitLength() + ","
229                + getOverflow().toString() + "," + getRounding().toString()
230                + ")";
231    }
232
233    ///////////////////////////////////////////////////////////////////
234    ////                         private variables                 ////
235
236    /** The precision. */
237    protected Precision _precision = null;
238}