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}