001/* A token that contains a double precision number.
002
003 Copyright (c) 1998-2015 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.data;
029
030import ptolemy.data.type.BaseType;
031import ptolemy.data.type.Type;
032import ptolemy.data.type.TypeLattice;
033import ptolemy.data.unit.UnitUtilities;
034import ptolemy.graph.CPO;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.math.Complex;
037
038///////////////////////////////////////////////////////////////////
039//// DoubleToken
040
041/**
042 A token that contains a 64-bit signed mantissa, signed exponent double
043 precision floating-point number (IEEE 754).  This class handles overflow and
044 underflow as does normal java arithmetic on doubles.
045
046 <p> Note that a double cannot be losslessly converted to a long, and
047 vice versa, as both have 64-bit representations in Java.
048
049 @see ptolemy.data.Token
050 @author Neil Smyth, Yuhong Xiong, Christopher Hylands, Steve Neuendorffer
051 @version $Id$
052 @since Ptolemy II 0.2
053 @Pt.ProposedRating Yellow (cxh) nil token, ONE, ZERO
054 @Pt.AcceptedRating Red (cxh)
055 */
056public class DoubleToken extends ScalarToken {
057    /** Construct a DoubleToken with value 0.0.
058     */
059    public DoubleToken() {
060        _value = 0.0;
061    }
062
063    /** Construct a DoubleToken with the specified value.
064     *  @param value The specified value.
065     */
066    public DoubleToken(double value) {
067        _value = value;
068    }
069
070    /** Construct a DoubleToken from the specified string.
071     *  @param init The initialization string, which is in a format
072     *  suitable for java.lang.Double.parseDouble(String).
073     *  @exception IllegalActionException If the Token could not
074     *   be created with the given String.
075     */
076    public DoubleToken(String init) throws IllegalActionException {
077        if (init == null || init.equals("nil")) {
078            throw new IllegalActionException(
079                    notSupportedNullNilStringMessage("DoubleToken", init));
080        }
081        try {
082            _value = Double.parseDouble(init);
083        } catch (NumberFormatException e) {
084            throw new IllegalActionException(null, e,
085                    "Failed to parse \"" + init + "\" as a number.");
086        }
087    }
088
089    ///////////////////////////////////////////////////////////////////
090    ////                         public methods                    ////
091
092    /** Return the value of this token as a Complex. The real part
093     *  of the Complex is the value of this token, the imaginary part
094     *  is set to 0.
095     *  @return A Complex
096     */
097    @Override
098    public Complex complexValue() {
099        return new Complex(_value, 0.0);
100    }
101
102    /** Convert the specified token into an instance of DoubleToken.
103     *  This method does lossless conversion.  The units of the
104     *  returned token will be the same as the units of the given
105     *  token.  If the argument is already an instance of DoubleToken,
106     *  it is returned without any change. If it is a PetiteToken is
107     *  it returned as a DoubleToken since lossless conversion is
108     *  possible between PetiteToken and DoubleToken.  If the argument
109     *  is a nil token, then {@link #NIL} is
110     *  returned.  Otherwise, if the argument is below DoubleToken in
111     *  the type hierarchy, it is converted to an instance of
112     *  DoubleToken or one of the subclasses of DoubleToken and
113     *  returned. If none of the above condition is met, an exception
114     *  is thrown.
115     *
116     *  @param token The token to be converted to a DoubleToken.
117     *  @return A DoubleToken.
118     *  @exception IllegalActionException If the conversion
119     *   cannot be carried out.
120     */
121    public static DoubleToken convert(Token token)
122            throws IllegalActionException {
123        if (token instanceof DoubleToken) {
124            // Since PetiteToken extends DoubleToken, if the token arg
125            // is a Petite, then we will return a Double from here.
126            return (DoubleToken) token;
127        }
128        if (token.isNil()) {
129            return DoubleToken.NIL;
130        }
131        int compare = TypeLattice.compare(BaseType.DOUBLE, token);
132
133        if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) {
134            throw new IllegalActionException(
135                    notSupportedIncomparableConversionMessage(token, "double"));
136        }
137
138        compare = TypeLattice.compare(BaseType.FLOAT, token);
139
140        if (compare == CPO.SAME || compare == CPO.HIGHER) {
141            FloatToken floatToken = FloatToken.convert(token);
142            DoubleToken result = new DoubleToken(floatToken.doubleValue());
143            if (floatToken._unitCategoryExponents != null && !UnitUtilities
144                    .isUnitless(floatToken._unitCategoryExponents)) {
145                result._unitCategoryExponents = floatToken
146                        ._copyOfCategoryExponents();
147            }
148            return result;
149        }
150
151        compare = TypeLattice.compare(BaseType.INT, token);
152
153        if (compare == CPO.SAME || compare == CPO.HIGHER) {
154            IntToken intToken = IntToken.convert(token);
155            DoubleToken result = new DoubleToken(intToken.doubleValue());
156            if (intToken._unitCategoryExponents != null && !UnitUtilities
157                    .isUnitless(intToken._unitCategoryExponents)) {
158                result._unitCategoryExponents = intToken
159                        ._copyOfCategoryExponents();
160            }
161            return result;
162        } else {
163            throw new IllegalActionException(
164                    notSupportedConversionMessage(token, "double"));
165        }
166    }
167
168    /** Return the value in the token as a double.
169     *  @return The value contained in this token as a double.
170     */
171    @Override
172    public double doubleValue() {
173        return _value;
174    }
175
176    /** Return true if the argument's class is DoubleToken and it has the
177     *  same values as this token.
178     *  @param object An instance of Object.
179     *  @return True if the argument is a DoubleToken with the same
180     *  value. If either this object or the argument is a nil Token, return
181     *  false.
182     */
183    @Override
184    public boolean equals(Object object) {
185        if (object == null) {
186            return false;
187        }
188        // This test rules out subclasses.
189        if (object.getClass() != getClass()) {
190            return false;
191        }
192
193        if (isNil() || ((DoubleToken) object).isNil()) {
194            return false;
195        }
196
197        if (((DoubleToken) object).doubleValue() == _value) {
198            return true;
199        }
200
201        return false;
202    }
203
204    /** Return the type of this token.
205     *  @return BaseType.DOUBLE
206     */
207    @Override
208    public Type getType() {
209        return BaseType.DOUBLE;
210    }
211
212    /** Return a hash code value for this token. This method returns the
213     *  integer portion of the contained double.
214     *  @return A hash code value for this token.
215     */
216    @Override
217    public int hashCode() {
218        return (int) _value;
219    }
220
221    /** Return true if the token is nil, (aka null or missing).
222     *  Nil or missing tokens occur when a data source is sparsely populated.
223     *  @return True if the token is the {@link #NIL} token.
224     */
225    @Override
226    public boolean isNil() {
227        // We use a method here so that we can easily change how
228        // we determine if a token is nil without modify lots of classes.
229        return this == DoubleToken.NIL;
230    }
231
232    /** Returns a DoubleToken with value 1.0.
233     *  @return A DoubleToken with value 1.0.
234     */
235    @Override
236    public Token one() {
237        return ONE;
238    }
239
240    /** Return the value of this token as a string that can be parsed
241     *  by the expression language to recover a token with the same value.
242     *  The exact form of the number depends on its value, and may be either
243     *  decimal or exponential.  In general, exponential is used for numbers
244     *  whose magnitudes are very large or very small, except for zero which
245     *  is always represented as 0.0.  The behavior is roughly the same as
246     *  Double.toString(), except that we limit the precision to seven
247     *  fractional digits.  If you really must have better precision,
248     *  then use <code>Double.toString(token.doubleValue())</code>.
249     *  If this token has a unit, the return string also includes a unit
250     *  string produced by the unitsString() method in the super class.
251     *  @return A String representing the double value and the units (if
252     *   any) of this token.
253     *  @see ptolemy.data.ScalarToken#unitsString
254     */
255    @Override
256    public String toString() {
257        String unitString = "";
258
259        if (!_isUnitless()) {
260            unitString = " * " + unitsString();
261        }
262
263        if (isNil()) {
264            // FIXME: what about units?
265            return super.toString();
266        }
267
268        if (Double.isNaN(_value) || Double.isInfinite(_value)) {
269            return Double.toString(_value) + unitString;
270        } else {
271            double mag = Math.abs(_value);
272
273            if (mag == 0.0 || mag < 1000000 && mag > .001) {
274                return TokenUtilities.regularFormat.format(_value) + unitString;
275            } else {
276                return TokenUtilities.exponentialFormat.format(_value)
277                        + unitString;
278            }
279        }
280    }
281
282    /** Returns a DoubleToken with value 0.0.
283     *  @return A DoubleToken with value 0.0.
284     */
285    @Override
286    public Token zero() {
287        return ZERO;
288    }
289
290    ///////////////////////////////////////////////////////////////////
291    ////                         public variables                  ////
292
293    /** A token that represents a missing value.
294     *  Null or missing tokens are common in analytical systems
295     *  like R and SAS where they are used to handle sparsely populated data
296     *  sources.  In database parlance, missing tokens are sometimes called
297     *  null tokens.  Since null is a Java keyword, we use the term "nil".
298     *  The toString() method on a nil token returns the string "nil".
299     */
300    public static final DoubleToken NIL = new DoubleToken(Double.NaN);
301
302    /** A DoubleToken with the value 1.0. */
303    public static final DoubleToken ONE = new DoubleToken(1);
304
305    /** A DoubleToken with the value 0.0. */
306    public static final DoubleToken ZERO = new DoubleToken(0);
307
308    ///////////////////////////////////////////////////////////////////
309    ////                         protected methods                 ////
310
311    /** Return a ScalarToken containing the absolute value of the
312     *  value of this token. If this token contains a non-negative
313     *  number, it is returned directly; otherwise, a new token is is
314     *  return.  Note that it is explicitly allowable to return this
315     *  token, since the units are the same.
316     *  @return An DoubleToken.
317     */
318    @Override
319    protected ScalarToken _absolute() {
320        DoubleToken result;
321
322        if (_value >= 0.0) {
323            result = this;
324        } else {
325            result = new DoubleToken(-_value);
326        }
327
328        return result;
329    }
330
331    /** Return a new token whose value is the value of the
332     *  argument Token added to the value of this Token.  It is assumed
333     *  that the type of the argument is an DoubleToken.
334     *  @param rightArgument The token to add to this token.
335     *  @return A new DoubleToken containing the result.
336     */
337    @Override
338    protected ScalarToken _add(ScalarToken rightArgument) {
339        // If the right argument is a SmoothToken, then delegate to it so that
340        // derivatives are preserved.
341        if (rightArgument instanceof SmoothToken) {
342            return ((SmoothToken) rightArgument)._add(this);
343        }
344        double sum = _value + ((DoubleToken) rightArgument).doubleValue();
345        return new DoubleToken(sum);
346    }
347
348    /** Returns a token representing the bitwise AND of this token and
349     *  the given token.
350     *  @param rightArgument The DoubleToken to bitwise AND with this one.
351     *  @return The bitwise AND.
352     *  @exception IllegalActionException Always thrown by this base class.
353     */
354    @Override
355    protected ScalarToken _bitwiseAnd(ScalarToken rightArgument)
356            throws IllegalActionException {
357        throw new IllegalActionException(
358                notSupportedMessage("bitwiseAnd", this, rightArgument));
359    }
360
361    /** Returns a token representing the bitwise NOT of this token.
362     *  @return The bitwise NOT of this token.
363     *  @exception IllegalActionException Always thrown by this base class.
364     */
365    @Override
366    protected ScalarToken _bitwiseNot() throws IllegalActionException {
367        throw new IllegalActionException(
368                notSupportedMessage("bitwiseNot", this, this));
369    }
370
371    /** Returns a token representing the bitwise OR of this token and
372     *  the given token.
373     *  @param rightArgument The DoubleToken to bitwise OR with this one.
374     *  @return The bitwise OR.
375     *  @exception IllegalActionException Always thrown by this base class.
376     */
377    @Override
378    protected ScalarToken _bitwiseOr(ScalarToken rightArgument)
379            throws IllegalActionException {
380        throw new IllegalActionException(
381                notSupportedMessage("bitwiseOr", this, rightArgument));
382    }
383
384    /** Returns a token representing the bitwise XOR of this token and
385     *  the given token.
386     *  @param rightArgument The DoubleToken to bitwise XOR with this one.
387     *  @return The bitwise XOR.
388     *  @exception IllegalActionException Always thrown by this base class.
389     */
390    @Override
391    protected ScalarToken _bitwiseXor(ScalarToken rightArgument)
392            throws IllegalActionException {
393        throw new IllegalActionException(
394                notSupportedMessage("bitwiseXor", this, rightArgument));
395    }
396
397    /** Return a new token whose value is the value of this token
398     *  divided by the value of the argument token. It is assumed that
399     *  the type of the argument is an DoubleToken
400     *  @param divisor The token to divide this token by.
401     *  @return A new DoubleToken containing the result.
402     */
403    @Override
404    protected ScalarToken _divide(ScalarToken divisor) {
405        double quotient = _value / ((DoubleToken) divisor).doubleValue();
406        return new DoubleToken(quotient);
407    }
408
409    /** Test that the value of this token is close to the first
410     *  argument, where "close" means that the distance between their
411     *  values is less than or equal to the second argument. It is
412     *  assumed that the type of the first argument is DoubleToken.
413     *  @param rightArgument The token to compare to this token.
414     *  @param epsilon The distance.
415     *  @return A token containing tue if the value of this token is close
416     *   to that of the argument.
417     */
418    @Override
419    protected BooleanToken _isCloseTo(ScalarToken rightArgument,
420            double epsilon) {
421        // NOTE: This code is duplicated in
422        // ptolemy.math.DoubleMatrixMath.within(); if this
423        // implementation changes, also change the corresponding
424        // implementation there.
425        // NOTE: Used to compare against epsilon the following expression:
426        // Math.abs(doubleValue() - ((DoubleToken)rightArgument).doubleValue()))
427        // However, because of quantization errors, this did not work well.
428        double right = ((DoubleToken) rightArgument).doubleValue();
429        double left = doubleValue();
430
431        if (right > left + epsilon || right < left - epsilon) {
432            return BooleanToken.FALSE;
433        } else {
434            return BooleanToken.TRUE;
435        }
436    }
437
438    /** Test for ordering of the values of this Token and the argument
439     *  Token.  It is assumed that the type of the argument is DoubleToken.
440     *  @param rightArgument The token to compare to this token.
441     *  @exception IllegalActionException If this method is not
442     *  supported by the derived class.
443     *  @return A new Token containing the result.
444     */
445    @Override
446    protected BooleanToken _isLessThan(ScalarToken rightArgument)
447            throws IllegalActionException {
448        DoubleToken convertedArgument = (DoubleToken) rightArgument;
449        return BooleanToken
450                .getInstance(_value < convertedArgument.doubleValue());
451    }
452
453    /** Return a new token whose value is the value of this token
454     *  modulo the value of the argument token.  It is assumed that
455     *  the type of the argument is an DoubleToken.
456     *  @param rightArgument The token to modulo this token by.
457     *  @return A new DoubleToken containing the result.
458     */
459    @Override
460    protected ScalarToken _modulo(ScalarToken rightArgument) {
461        double remainder = _value % ((DoubleToken) rightArgument).doubleValue();
462        return new DoubleToken(remainder);
463    }
464
465    /** Return a new token whose value is the value of this token
466     *  multiplied by the value of the argument token.  It is assumed that
467     *  the type of the argument is an DoubleToken.
468     *  @param rightArgument The token to multiply this token by.
469     *  @return A new DoubleToken containing the result.
470     */
471    @Override
472    protected ScalarToken _multiply(ScalarToken rightArgument) {
473        // If the right argument is a SmoothToken, then delegate to it so that
474        // derivatives are preserved.
475        if (rightArgument instanceof SmoothToken) {
476            return ((SmoothToken) rightArgument)._multiply(this);
477        }
478        double product = _value * ((DoubleToken) rightArgument).doubleValue();
479        return new DoubleToken(product);
480    }
481
482    /** Return a new token whose value is the value of the argument token
483     *  subtracted from the value of this token.  It is assumed that
484     *  the type of the argument is an DoubleToken.
485     *  @param rightArgument The token to subtract from this token.
486     *  @return A new DoubleToken containing the result.
487     */
488    @Override
489    protected ScalarToken _subtract(ScalarToken rightArgument) {
490        // If the right argument is a SmoothToken, then delegate to it so that
491        // derivatives are preserved.
492        if (rightArgument instanceof SmoothToken) {
493            SmoothToken negative = ((SmoothToken) rightArgument).negate();
494            return negative._add(this);
495        }
496        double difference = _value
497                - ((DoubleToken) rightArgument).doubleValue();
498        return new DoubleToken(difference);
499    }
500
501    ///////////////////////////////////////////////////////////////////
502    ////                         protected variables               ////
503
504    /** The double value.  Derived constructors may set this variable,
505     *  but after it is set in the constructor it should not be modified.
506     */
507    protected double _value;
508}