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}