001/** A token that contains a FixPoint number.
002
003 Copyright (c) 1998-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 DISCL5AIMS 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.data;
030
031import ptolemy.data.expr.ASTPtRootNode;
032import ptolemy.data.expr.ParseTreeEvaluator;
033import ptolemy.data.expr.PtParser;
034import ptolemy.data.type.BaseType;
035import ptolemy.data.type.FixType;
036import ptolemy.data.type.Type;
037import ptolemy.data.type.TypeLattice;
038import ptolemy.graph.CPO;
039import ptolemy.kernel.util.IllegalActionException;
040import ptolemy.math.FixPoint;
041import ptolemy.math.FixPointQuantization;
042import ptolemy.math.Overflow;
043import ptolemy.math.Precision;
044import ptolemy.math.Quantization;
045import ptolemy.math.Rounding;
046
047///////////////////////////////////////////////////////////////////
048//// FixToken
049
050/**
051 A token that contains an instance of FixPoint.
052
053 @author Bart Kienhuis, Edward A. Lee, Steve Neuendorffer Ed Willink
054 @see ptolemy.data.Token
055 @see ptolemy.math.FixPoint
056 @see ptolemy.math.FixPointQuantization
057 @see ptolemy.math.Precision
058 @see ptolemy.math.Quantization
059 @version $Id$
060 @since Ptolemy II 0.4
061 @Pt.ProposedRating Yellow (kienhuis)
062 @Pt.AcceptedRating Yellow (kienhuis)
063 */
064public class FixToken extends ScalarToken { // implements BitwiseOperationToken {
065
066    /** Construct a token with integer 0.
067     *  This method calls the {@link ptolemy.math.FixPoint#FixPoint(int)}
068     *  constructor, so the precision and quantization are the what ever
069     *  is defined for that constructor
070     */
071    public FixToken() {
072        _value = new FixPoint(0);
073    }
074
075    /** Construct a FixToken with the supplied FixPoint value.
076     *  @param value A FixPoint value.
077     */
078    public FixToken(FixPoint value) {
079        _value = value;
080    }
081
082    // FIXME: The constructors should throw IllegalActionException instead of
083    // IllegalArgumentException. But since the FixPointFunctions class in the
084    // expression package does not catch IllegalActionException, leave
085    // IllegalArgumentException for now.
086
087    /** Construct a FixToken representing the specified value with the
088     *  specified precision.  The specified value is quantized to the
089     *  closest value representable with the specified precision.
090     *
091     *  @param value The value to represent.
092     *  @param precision The precision to use.
093     *  @exception IllegalArgumentException If the supplied precision
094     *   is invalid.
095     */
096    public FixToken(double value, Precision precision)
097            throws IllegalArgumentException {
098        try {
099            FixPointQuantization q = new FixPointQuantization(precision,
100                    Overflow.SATURATE, Rounding.NEAREST);
101            _value = new FixPoint(value, q);
102        } catch (NumberFormatException e) {
103            throw new IllegalArgumentException(e.getMessage());
104        }
105    }
106
107    /** Construct a FixToken representing the specified value with the
108     *  specified precision.  The specified value is quantized to the
109     *  closest value representable with the specified precision.
110     *
111     *  @param value The value to represent.
112     *  @param numberOfBits The total number of bits.
113     *  @param integerBits The number of integer bits.
114     *  @exception IllegalArgumentException If the supplied precision
115     *   is invalid.
116     */
117    public FixToken(double value, int numberOfBits, int integerBits)
118            throws IllegalArgumentException {
119        try {
120            Precision precision = new Precision(numberOfBits, integerBits);
121            FixPointQuantization q = new FixPointQuantization(precision,
122                    Overflow.SATURATE, Rounding.NEAREST);
123            _value = new FixPoint(value, q);
124        } catch (NumberFormatException e) {
125            throw new IllegalArgumentException(e.getMessage());
126        }
127    }
128
129    /** Construct a FixToken from the specified string.
130     *  @param init A string expression of a fixed point number in Ptolemy II
131     *   expression language syntax.
132     *  @exception IllegalActionException If the string does
133     *   not contain a parsable fixed point number.
134     */
135    public FixToken(String init) throws IllegalActionException {
136        PtParser parser = new PtParser();
137        ASTPtRootNode tree = parser.generateParseTree(init);
138        Token token = new ParseTreeEvaluator().evaluateParseTree(tree);
139
140        if (token instanceof FixToken) {
141            _value = ((FixToken) token).fixValue();
142        } else {
143            throw new IllegalActionException("A FixToken cannot be"
144                    + " created from the expression '" + init + "'");
145        }
146    }
147
148    ///////////////////////////////////////////////////////////////////
149    ////                         public methods                    ////
150
151    /** Convert the specified token into an instance of FixToken.
152     *  This method does lossless conversion.  The units of the
153     *  returned token will be the same as the units of the given
154     *  token.  If the argument is already an instance of FixToken, it
155     *  is returned without any change. Otherwise, if the argument is
156     *  below FixToken in the type hierarchy, it is converted to an
157     *  instance of FixToken or one of the subclasses of FixToken and
158     *  returned. If none of the above conditions are met, an
159     *  exception is thrown.
160     *  @param token The token to be converted to a FixToken.
161     *  @return A FixToken.
162     *  @exception IllegalActionException If the conversion
163     *  cannot be carried out.
164     */
165    public static FixToken convert(Token token) throws IllegalActionException {
166        if (token instanceof FixToken) {
167            return (FixToken) token;
168        }
169
170        int compare = TypeLattice.compare(BaseType.FIX, token);
171
172        if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) {
173            throw new IllegalActionException(
174                    notSupportedIncomparableConversionMessage(token, "fix"));
175        }
176
177        throw new IllegalActionException(
178                notSupportedConversionMessage(token, "fix"));
179    }
180
181    /** Return the fixed point value of this token as a double. The
182     *  conversion from a fixed point to a double is not lossless, so
183     *  the doubleValue() cannot be used. Therefore an explicit lossy
184     *  conversion method is provided.
185     *  @return A double representation of the value of this token.
186     */
187    public double convertToDouble() {
188        return _value.doubleValue();
189    }
190
191    /** Return true if the argument's class is IntToken and it has the
192     *  same values as this token.
193     *  @param object An instance of Object.
194     *  @return True if the argument is a FixToken with the
195     *  same value.
196     */
197    @Override
198    public boolean equals(Object object) {
199        if (object == null) {
200            return false;
201        }
202        // This test rules out subclasses.
203        if (object.getClass() != getClass()) {
204            return false;
205        }
206
207        if (((FixToken) object).fixValue().equals(_value)) {
208            return true;
209        }
210
211        return false;
212    }
213
214    /** Return the value of this token as a FixPoint.
215     *  @return A FixPoint.
216     */
217    @Override
218    public FixPoint fixValue() {
219        return _value;
220    }
221
222    /** Return the type of this token.
223     *  @return an instance of FixType;
224     */
225    @Override
226    public Type getType() {
227        return new FixType(_value.getPrecision());
228    }
229
230    /** Return a hash code value for this value. This method returns the
231     *  low order 32 bits of the integer representation.
232     *  @return A hash code value for this token.
233     */
234    @Override
235    public int hashCode() {
236        return _value.hashCode();
237    }
238
239    /** Returns a new Token representing the multiplicative identity
240     *  with the same precision as this FixToken.
241     *  @return A new FixToken with value 1.0.
242     */
243    @Override
244    public Token one() {
245        return new FixToken(1.0, _value.getPrecision());
246    }
247
248    /** Print the content of this FixToken: This is used for debugging
249     *  only.
250     */
251    public void print() {
252        _value.printFix();
253    }
254
255    /** Return a new token whose value is constrained to comply
256     *  with a quantization specification.
257     *  @param quant The quantization specification.
258     *  @return A new FixToken containing the result.
259     */
260    public final FixToken quantize(Quantization quant) {
261        //FIXME: Move this to ScalarToken.
262        FixToken result = _quantize(quant);
263        if (_unitCategoryExponents != null && !_isUnitless()) {
264            result._unitCategoryExponents = _copyOfCategoryExponents();
265        }
266        return result;
267    }
268
269    /** Return the value of this token as a string that can be parsed
270     *  by the expression language to recover a token with the same
271     *  value. The "fix" keyword indicates it is a FixToken. The first
272     *  argument is the decimal value, the second is the total number
273     *  of bits and the third is the number of bits for the integer
274     *  portion. For more information about these arguments, see the
275     *  three argument constructor.
276     *
277     *  @return A String representing of this Token.
278     */
279    @Override
280    public String toString() {
281        String unitString = "";
282
283        if (!_isUnitless()) {
284            unitString = " * " + unitsString();
285        }
286
287        Precision precision = _value.getPrecision();
288        return "fix(" + _value.toString() + "," + precision.getNumberOfBits()
289                + "," + precision.getIntegerBitLength() + ")" + unitString;
290    }
291
292    /** Return a new token representing the additive identity with
293     *  the same precision as this FixToken.
294     *  @return A new FixToken with value 0.0.
295     */
296    @Override
297    public Token zero() {
298        return new FixToken(0.0, _value.getPrecision());
299    }
300
301    ///////////////////////////////////////////////////////////////////
302    ////                         protected methods                 ////
303
304    /** Return a ScalarToken containing the absolute value of the
305     *  value of this token. If this token contains a non-negative
306     *  number, it is returned directly; otherwise, a new token is is
307     *  return.  Note that it is explicitly allowable to return this
308     *  token, since the units are the same.
309     *  @return A FixToken.
310     */
311    @Override
312    protected ScalarToken _absolute() {
313        FixToken result = new FixToken(_value.abs());
314        return result;
315    }
316
317    /** Return a new token whose value is the value of the
318     *  argument Token added to the value of this Token.  It is assumed
319     *  that the type of the argument is an FixToken.
320     *  @param rightArgument The token to add to this token.
321     *  @return A new FixToken containing the result.
322     */
323    @Override
324    protected ScalarToken _add(ScalarToken rightArgument) {
325        FixPoint result = _value.add(((FixToken) rightArgument).fixValue());
326        return new FixToken(result);
327    }
328
329    /** Returns a token representing the bitwise AND of this token and
330     *  the given token.
331     *  @param rightArgument The FixToken to bitwise AND with this one.
332     *  @return The bitwise AND.
333     *  @exception IllegalActionException If the given token is not
334     *  compatible for this operation, or the operation does not make
335     *  sense for this type.
336     */
337    @Override
338    protected ScalarToken _bitwiseAnd(ScalarToken rightArgument)
339            throws IllegalActionException {
340        throw new IllegalActionException(
341                notSupportedMessage("bitwiseAnd", this, rightArgument));
342    }
343
344    /** Returns a token representing the bitwise NOT of this token.
345     *  @return The bitwise NOT of this token.
346     *  @exception IllegalActionException If the given token is not
347     *  compatible for this operation, or the operation does not make
348     *  sense for this type.
349     */
350    @Override
351    protected ScalarToken _bitwiseNot() throws IllegalActionException {
352        throw new IllegalActionException(
353                notSupportedMessage("bitwiseNot", this, this));
354    }
355
356    /** Returns a token representing the bitwise OR of this token and
357     *  the given token.
358     *  @param rightArgument The FixToken to bitwise OR with this one.
359     *  @return The bitwise OR.
360     *  @exception IllegalActionException If the given token is not
361     *  compatible for this operation, or the operation does not make
362     *  sense for this type.
363     */
364    @Override
365    protected ScalarToken _bitwiseOr(ScalarToken rightArgument)
366            throws IllegalActionException {
367        throw new IllegalActionException(
368                notSupportedMessage("bitwiseOr", this, rightArgument));
369    }
370
371    /** Returns a token representing the bitwise XOR of this token and
372     *  the given token.
373     *  @param rightArgument The FixToken to bitwise XOR with this one.
374     *  @return The bitwise XOR.
375     *  @exception IllegalActionException If the given token is not
376     *  compatible for this operation, or the operation does not make
377     *  sense for this type.
378     */
379    @Override
380    protected ScalarToken _bitwiseXor(ScalarToken rightArgument)
381            throws IllegalActionException {
382        throw new IllegalActionException(
383                notSupportedMessage("bitwiseXor", this, rightArgument));
384    }
385
386    /** Return a new token whose value is the value of this token
387     *  divided by the value of the argument token. It is assumed that
388     *  the type of the argument is an FixToken
389     *  @param rightArgument The token to divide this token by.
390     *  @return A new FixToken containing the result.
391     */
392    @Override
393    protected ScalarToken _divide(ScalarToken rightArgument) {
394        FixPoint result = _value.divide(((FixToken) rightArgument).fixValue());
395        return new FixToken(result);
396    }
397
398    /** Return a new token whose value is the value of this token
399     *  divided by the value of the argument token. It is assumed that
400     *  the type of the argument is an FixToken
401     *  @param rightArgument The token to divide this token by.
402     *  @param quant The quantization specification.
403     *  @return A new FixToken containing the result.
404     */
405    protected ScalarToken _divide(ScalarToken rightArgument,
406            Quantization quant) {
407        FixPoint result = _value.divide(((FixToken) rightArgument).fixValue(),
408                quant);
409        return new FixToken(result);
410    }
411
412    /** Test whether the value of this token is close to the first argument,
413     *  where "close" means that the distance between their values is less than
414     *  or equal to the second argument. It is assumed that the type of
415     *  the first argument is FixToken.  NOTE: Both the value of this token
416     *  and the token to compare are converted to double using
417     *         convertToDouble() before the comparison is made.
418     *  @param rightArgument The token to compare to this token.
419     *  @param epsilon The value that we use to determine whether two
420     *   tokens are close.
421     *  @return A token containing true if the value of the first
422     *   argument is close to the value of this token.
423     */
424    @Override
425    protected BooleanToken _isCloseTo(ScalarToken rightArgument,
426            double epsilon) {
427        double right = ((FixToken) rightArgument).convertToDouble();
428        double left = convertToDouble();
429
430        if (right > left + epsilon || right < left - epsilon) {
431            return BooleanToken.FALSE;
432        } else {
433            return BooleanToken.TRUE;
434        }
435    }
436
437    /** Test for ordering of the values of this Token and the argument
438     *  Token.  It is assumed that the type of the argument is FixToken.
439     *  @param rightArgument The token to add to this token.
440     *  @exception IllegalActionException If this method is not
441     *  supported by the derived class.
442     *  @return A new Token containing the result.
443     */
444    @Override
445    protected BooleanToken _isLessThan(ScalarToken rightArgument)
446            throws IllegalActionException {
447        FixToken convertedArgument = (FixToken) rightArgument;
448        return BooleanToken.getInstance(_value.doubleValue() < convertedArgument
449                .fixValue().doubleValue());
450    }
451
452    /** Return a new token whose value is the value of this token
453     *  modulo the value of the argument token.  It is assumed
454     *  that the type of the argument is the same as the type of this class.
455     *  @param rightArgument The token to modulo this token by.
456     *  @exception IllegalActionException If this method is not
457     *   supported by the derived class.
458     *  @return A new Token containing the result that is of the same class
459     *  as this token.
460     */
461    @Override
462    protected ScalarToken _modulo(ScalarToken rightArgument)
463            throws IllegalActionException {
464        throw new IllegalActionException(
465                notSupportedMessage("modulo", this, rightArgument));
466    }
467
468    /** Return a new token whose value is the value of this token
469     *  multiplied by the value of the argument token.  It is assumed that
470     *  the type of the argument is an FixToken.
471     *  @param rightArgument The token to multiply this token by.
472     *  @return A new FixToken containing the result.
473     */
474    @Override
475    protected ScalarToken _multiply(ScalarToken rightArgument) {
476        FixPoint result = _value
477                .multiply(((FixToken) rightArgument).fixValue());
478        return new FixToken(result);
479    }
480
481    /** Return a new token whose value is constrained to comply
482     *  with a quantization specification.
483     *  @param quant The quantization specification.
484     *  @return A new FixToken containing the result.
485     */
486    protected FixToken _quantize(Quantization quant) {
487        FixPoint result = _value.quantize(quant);
488        return new FixToken(result);
489    }
490
491    /** Return a new token whose value is the value of the argument token
492     *  subtracted from the value of this token.  It is assumed that
493     *  the type of the argument is an FixToken.
494     *  @param rightArgument The token to subtract from this token.
495     *  @return A new FixToken containing the result.
496     */
497    @Override
498    protected ScalarToken _subtract(ScalarToken rightArgument) {
499        FixPoint result = _value
500                .subtract(((FixToken) rightArgument).fixValue());
501        return new FixToken(result);
502    }
503
504    ///////////////////////////////////////////////////////////////////
505    ////                         private variables                 ////
506
507    /** The FixPoint value contained in this FixToken. */
508    private FixPoint _value;
509}