/** A class defining quantization to a FixPoint number. Copyright (c) 2002-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.math; import java.math.BigInteger; /** The Quantization class defines the mapping of numeric values with unlimited precision to finite precision.

It comprises a

The way in which precision is realised is a sub-class responsibility. The standard fixed point binary functionality using a Precision is provided by FixPointQuantization.

This abstract class is designed to support specification of required numeric behavior through use of the yet-to-be-written FloatingQuantization and FixedQuantization classes. Knowledge of the required numeric behavior, rather than precise specification of an exact implementation, provides an opportunity for code generation to select appropriate types supported by a target architecture.

FixedQuantization provides for modulo equi-spaced values between the inclusive maximum and minimum limits. epsilon, the separation between values is given by (maximum - minimum) / (modulo - 1). Whether values beyond the maximum and minimum wrap-around is determined by the overflow strategy. FixedQuantization therefore describes the requirements of a single fixed point range comprising just a mantissa.

FloatingQuantization adds an exponent to support multiple floating point ranges; maximum defines the upper limit of the coarsest scale and tiny defines the smallest representable non-zero number on the finest scale. (tiny is the same as epsilon for FixedQuantization.)

If exactRounding is specified, code generation must ensure that arithmetic rounds to the specified epsilon. Otherwise, the code generator may use arithmetic with higher precision.

If exactOverflow is specified, code generation must ensure that arithmetic overflows saturate or wrap-around at the specified maximum and minimum. Otherwise, the code generator may use arithmetic with greater range.

The active class functionality is provided by the quantize method, which is normally invoked from FixPoint.quantize or ScalarToken.quantize to enforce quantization constraints upon the result of an unconstrained computation.

An instance of the class is immutable, meaning that its value is set in the constructor and cannot then be modified. @author Ed Willink @version $Id: Quantization.java 69607 2014-07-30 17:07:26Z cxh $ @since Ptolemy II 2.1 @Pt.ProposedRating Red (Ed.Willink) @Pt.AcceptedRating Red @see ptolemy.math.FixPoint @see ptolemy.math.FixPointQuantization @see ptolemy.math.Precision @see ptolemy.math.Overflow @see ptolemy.math.Rounding */ public abstract class Quantization implements Cloneable { /** Construct a Quantization with the given precision, overflow * strategy, and rounding strategy. * * @param overflow The Overflow object to use by this Quantization * strategy. * @param rounding The Rounding object to use by this Quantization * strategy. */ public Quantization(Overflow overflow, Rounding rounding) { _overflow = overflow; _rounding = rounding; } /////////////////////////////////////////////////////////////////// //// public methods //// /** Return this, that is, return the reference to this object. * @return This Quantization. */ @Override public Object clone() { return this; } /** Return true if the indicated object describes the same * mapping to quantized values. * * @param object The Quantization object to use for equality * checking. * @return True if the quantizations are equal. */ @Override public boolean equals(Object object) { if (object instanceof Quantization) { Quantization other = (Quantization) object; if (_overflow.equals(other._overflow) && _rounding.equals(other._rounding)) { return true; } } return false; } /** Return the separation between quantized values. * @return The quantization interval. */ public double getEpsilonValue() { double maxVal = getMaximumValue(); double minVal = getMinimumValue(); double modVal = getNumberOfLevels(); return (maxVal - minVal) / (modVal - 1.0); } /** Return the overflow bit-truth. * @return True if overflow must occur at the maximum and * minimum values, false if greater range is acceptable. */ public boolean getExactOverflow() { return false; } /** Return the rounding bit-truth. * @return True if rounding must occur exactly at epsilon, * false if finer resolution is acceptable. */ public boolean getExactRounding() { return false; } /** Return the number of bits to represent the exponent. * @return The length of the exponent. */ public int getExponentBitLength() { return 0; } /** Return the number of bits representing the fractional part * of the mantissa. * @return The length of the fractional part of the mantissa. */ public int getFractionBitLength() { return getMantissaPrecision().getFractionBitLength(); } /** Return the number of bits representing the integer part * of the mantissa. * @return The length of the integer part of the mantissa. */ public int getIntegerBitLength() { return getMantissaPrecision().getIntegerBitLength(); } /** Return the number of bits to represent the mantissa. * @return The length of the mantissa. */ public int getMantissaBitLength() { return getIntegerBitLength() + getFractionBitLength(); } /** Return the precision fore the mantissa of a compliant * 2's complement representation. * * @return The precision. */ public abstract Precision getMantissaPrecision(); /** Return the maximum quantizable value after scaling so that * quantization levels are represented by adjacent integers. * @return The maximum inclusive value. */ public BigInteger getMaximumUnscaledValue() { int numBits = getNumberOfBits(); return BigInteger.ZERO.setBit(numBits - 1).subtract(BigInteger.ONE); } /** Return the maximum quantizable value. * @return The maximum inclusive value. */ public double getMaximumValue() { double maxVal = getMaximumUnscaledValue().doubleValue(); return maxVal * Math.pow(0.5, getFractionBitLength()); } /** Return the minimum quantizable value after scaling so that * quantization levels are represented by adjacent integers. * @return The minimum inclusive value. */ public BigInteger getMinimumUnscaledValue() { int numBits = getNumberOfBits(); return BigInteger.ZERO.setBit(numBits - 1).negate(); } /** Return the minimum quantizable value. * @return The minimum inclusive value. */ public double getMinimumValue() { double minVal = getMinimumUnscaledValue().doubleValue(); return minVal * Math.pow(0.5, getFractionBitLength()); } /** Return the modulo quantization range after scaling so that * quantization levels are represented by adjacent integers. * This is the same as the number of quantization levels in * the mantissa.. * @return The modulo value. * @deprecated ? */ @Deprecated public BigInteger getModuloUnscaledValue() { int numBits = getNumberOfBits(); return BigInteger.ZERO.setBit(numBits); } /** Return the number of bits to represent the value. * @return The number of bits. */ public int getNumberOfBits() { return getMantissaBitLength() + getExponentBitLength(); } /** Return the number of quantization levels in the mantissa. * @return The number of levels. */ public double getNumberOfLevels() { return Math.pow(2.0, getMantissaBitLength()); } /** Return the overflow strategy. * @return The overflow strategy. */ public Overflow getOverflow() { return _overflow; } /** Return the Precision. * * @return The Precision object. */ public abstract Precision getPrecision(); /** Return the rounding strategy. * @return The rounding strategy. */ public Rounding getRounding() { return _rounding; } /** Return the quantizable value nearest to and above zero. * @return The positive value nearest to zero. */ public double getTinyValue() { return getEpsilonValue(); } /** Return a hash code value for this Quantization. This method returns the * bitwise and of the hashcode of the overflow and the hashcode of * the rounding. * @return A hash code value for this Quantization. */ @Override public int hashCode() { return _overflow.hashCode() & _rounding.hashCode(); } /** Return a string representing this quantization. * @return A string representing this quantization. */ @Override public abstract String toString(); /////////////////////////////////////////////////////////////////// //// private variables //// /** The overflow strategy. */ protected Overflow _overflow = Overflow.GENERAL; /** The rounding strategy. */ protected Rounding _rounding = Rounding.GENERAL; }