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}