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