001/* The overflow strategy classes. 002 003 Copyright (c) 2002-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.math; 029 030import java.math.BigInteger; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.Map; 034 035/////////////////////////////////////////////////////////////////// 036//// Overflow 037 038/** 039 The Overflow class provides a type safe enumeration of strategies for 040 handling numeric overflows for FixPoint data types. 041 Overflows are typically resolved after performing a FixPoint 042 arithmetic operation or transformation. 043 <p> 044 The active class functionality is provided by the 045 {@link #quantize(BigInteger, Precision) quantize} method. This method 046 evaluates an unscaled {@link BigInteger BigInteger} value and a 047 Precision constraint and creates a FixPoint object with a new 048 unscaled value and precision that conforms to the corresponding 049 overflow strategy. Depending on the overflow strategy used, 050 the unscaled integer value or the precision may be changed as 051 part of the overflow process. 052 <p> 053 The overflow strategies supported are as follows: 054 <ul> 055 056 <li> <i><b>grow</b></i> <br> 057 If the integer value does not fall within the dynamic range 058 of the Precision constraint, increase the Precision to the 059 minimum dynamic range needed to include the integerValue. 060 Note that the actual integer unscaled value will not change 061 during this overflow strategy. 062 This rounding mode is supported by the static 063 {@link #quantizeGrow(BigInteger, Precision) quantizeGrow} method 064 and the Overflow singletons {@link #GROW} and {@link #GENERAL}. 065 066 <li> <i><b>minimize</b></i> <br> 067 Represent the unscaled integer value with the minimum 068 number of data bits. The sign and exponent of the 069 new precision constraint is determined by the Precision 070 parameter. The use of this overflow strategy may increase 071 or decrease the Precision of the value. 072 Note that the actual integer unscaled value will not change 073 during this overflow strategy. 074 This rounding mode is supported by the static 075 {@link #quantizeMinimum(BigInteger, Precision) quantizeMinimize} 076 method and the Overflow singleton {@link #MINIMIZE} . 077 078 <li> <i><b>modulo</b></i> <br> 079 This overflow strategy will perform a twos complement modulo 080 operation any integer values that are outside of the 081 dynamic range of the Precision constraint. 082 Note that the actual precision will not change 083 during this overflow strategy. 084 This rounding mode is supported by the static 085 {@link #quantizeModulo(BigInteger, Precision) quantizeModulo} 086 method and the Overflow singletons {@link #MODULO} and {@link #WRAP}. 087 088 <li> <i><b>saturate</b></i> <br> 089 If the integer value falls outside of the Precision dynamic 090 range, this overflow strategy will saturate result. 091 If the value is below the minimum of the range, the 092 minimum value of the range is used. If the value is above 093 the maximum of the range, the maximum value of the range 094 is used. 095 Note that the precision will not change during this overflow strategy. 096 This rounding mode is supported by the static 097 {@link #quantizeSaturate(BigInteger, Precision) quantizeSaturate} 098 method and the Overflow singletons {@link #SATURATE} and 099 {@link #CLIP}. 100 101 <li> <i><b>to_zero</b></i> <br> 102 If the integer value falls outside of the Precision dynamic 103 range, this overflow strategy will set the integer value to zero. 104 Note that the actual precision will not change 105 during this overflow strategy. 106 This rounding mode is supported by the static 107 {@link #quantizeToZero(BigInteger, Precision) quantizeToZero} 108 method and the Overflow singleton {@link #TO_ZERO}. 109 110 <li> <i><b>trap</b></i> <br> 111 If the integer value falls outside of the Precision dynamic 112 range, a {@link java.lang.ArithmeticException} is generated. 113 This rounding mode is supported by the 114 singleton {@link #TRAP}. 115 </ul> 116 117 <p> 118 A specific strategy may be chosen dynamically by invoking 119 {@link #forName forName} or {@link #getName getName} 120 with one of the above strategy names. Alternatively a strategy 121 may be selected by using one of the static singletons. 122 <p> 123 Division by zero can trigger the use of the plusInfinity or minusInfinity 124 methods, which return null, except in the case of the <i>to_zero</i> 125 and <i>saturate</i> strategies for which infinity is well-defined. 126 127 @author Ed Willink 128 @version $Id$ 129 @since Ptolemy II 2.1 130 @Pt.ProposedRating Red (Ed.Willink) 131 @Pt.AcceptedRating Red 132 @see ptolemy.math.FixPoint 133 @see ptolemy.math.Quantization 134 @see ptolemy.math.Rounding 135 */ 136public abstract class Overflow implements Cloneable { 137 138 /////////////////////////////////////////////////////////////////// 139 //// public methods //// 140 141 /** Return this, that is, return the reference to this object. 142 * @return This Overflow. 143 */ 144 @Override 145 public Object clone() { 146 return this; 147 } 148 149 /** Determine if the argument represents the same Overflow as this 150 * object. 151 * @param object Another object. 152 * @return True if the argument represents the same Overflow as 153 * this object; false otherwise. 154 */ 155 @Override 156 public boolean equals(Object object) { 157 // since Overflow is a type safe enumeration, can use == to 158 // test equality. 159 return this == object; 160 } 161 162 /** Return an instance of this class with the specified name. 163 * 164 * @param name The name of the Overflow strategy to find. 165 * @return An instance of Overflow or null. 166 */ 167 public static Overflow forName(String name) { 168 return (Overflow) _nameToOverflow.get(name); 169 } 170 171 /** Return an instance of this class with the specified name, 172 * or null if none exists. 173 * 174 * @param name The name of the Overflow strategy to find. 175 * @return An instance of Overflow. 176 * @exception IllegalArgumentException If the string does not 177 * match one of the known strategies. 178 */ 179 public static Overflow getName(String name) 180 throws IllegalArgumentException { 181 Overflow overflow = (Overflow) _nameToOverflow.get(name); 182 183 if (overflow != null) { 184 return overflow; 185 } 186 187 throw new IllegalArgumentException( 188 "Unknown overflow strategy \"" + name + "\"."); 189 } 190 191 /** Return a hash code value for this object. 192 */ 193 @Override 194 public int hashCode() { 195 return _name.hashCode(); 196 } 197 198 /** 199 * Determines whether the given BigInteger unscaled value is considered 200 * an "underflow" or an "overflow" under the given Precision constraint. 201 * This will occur if the value is less than the minimum unscaled value of 202 * the given Precision constraint or more than the maximum unscaled value 203 * of the given Precision constraint. 204 * 205 * @param bigInt The value to test for underflow. 206 * @param precision The Precision constraint to use for the test. 207 * @return true if the value is considered an "underflow" or "overflow, 208 * false otherwise. 209 */ 210 public static boolean isOutOfRange(BigInteger bigInt, Precision precision) { 211 if (bigInt.compareTo(precision.getMaximumUnscaledValue()) > 0 212 || bigInt.compareTo(precision.getMinimumUnscaledValue()) < 0) { 213 return true; 214 } 215 return false; 216 } 217 218 /** 219 * Determines whether the given BigInteger unscaled value is considered 220 * an "overflow" under the given Precision constraint. This will occur 221 * if the value is larger than the maximum unscaled value of 222 * the given Precision constraint. 223 * (@see Precision#getMaximumUnscaledValue()) 224 * 225 * @param value The value to test for overflow. 226 * @param precision The Precision constraint to use for the test. 227 * @return true if the value is considered an "overflow", false if 228 * it is not an "overflow". 229 */ 230 public static boolean isOverflow(BigInteger value, Precision precision) { 231 if (value.compareTo(precision.getMaximumUnscaledValue()) > 0) { 232 return true; 233 } 234 return false; 235 } 236 237 /** 238 * Determines whether the given BigInteger unscaled value is considered 239 * an "underflow" under the given Precision constraint. This will occur 240 * if the value is less than the minimum unscaled value of 241 * the given Precision constraint. 242 * (@see Precision#getMinimumUnscaledValue()) 243 * 244 * @param bigInt The value to test for underflow. 245 * @param precision The Precision constraint to use for the test. 246 * @return true if the value is considered an "underflow", false if 247 * it is not an "underflow". 248 */ 249 public static boolean isUnderflow(BigInteger bigInt, Precision precision) { 250 if (bigInt.compareTo(precision.getMinimumUnscaledValue()) < 0) { 251 return true; 252 } 253 return false; 254 } 255 256 /** 257 * Return an iterator for the names of all overflow types. 258 * @return An iterator for the names of all overflow types. 259 */ 260 public static Iterator nameIterator() { 261 return _nameToOverflow.keySet().iterator(); 262 } 263 264 /** Return the value of minus infinity, or null if unrepresentable. 265 * <p> 266 * The saturation value is returned for the <i>saturate</i> and 267 * <i>to_zero</i> strategies for which infinity is quantizable. 268 * Null is returned for other strategies. 269 * 270 * @param quant The quantization specification. 271 * @return The value if defined, null if not.. 272 */ 273 public BigInteger minusInfinity(Quantization quant) { 274 return null; 275 } 276 277 /** Return the value of plus infinity, or null if unrepresentable. 278 * <p> 279 * The saturation value is returned for the <i>saturate</i> and 280 * <i>to_zero</i> strategies for which infinity is quantizable. 281 * Null is returned for other strategies. 282 * @param quant The quantization specification. 283 * @return The value if defined, null if not. 284 */ 285 public BigInteger plusInfinity(Quantization quant) { 286 return null; 287 } 288 289 /** Return a new FixPoint object based on the given BigInteger 290 * value and Precision constraint. This method will return 291 * a valid FixPoint object that conforms to the given 292 * overflow strategy implemented by the extending class. 293 * 294 * @param integerValue The unbounded integer value. 295 * @param precision The Precision constraint of the quantization. 296 * @return A valid FixPoint value that conforms to the overflow 297 * strategy. 298 */ 299 abstract public FixPoint quantize(BigInteger integerValue, 300 Precision precision); 301 302 /** 303 * Quantize a FixPoint value using a "grow" overflow strategy. 304 * If the Precision format does not provide sufficient dynamic range 305 * for the value, increase the Precision to the minimum dynamic range 306 * needed to include the integerValue. Note that the actual 307 * integer unscaled value will not change during this overflow 308 * strategy. 309 * 310 * @param integerValue unscaled integer value to check for overflow 311 * @param precision the precision constraint used for the overflow check 312 * @return Valid FixPoint data object 313 */ 314 public static FixPoint quantizeGrow(BigInteger integerValue, 315 Precision precision) { 316 if (isOutOfRange(integerValue, precision)) { 317 return quantizeMinimum(integerValue, precision); 318 } 319 return new FixPoint(integerValue, precision); 320 } 321 322 /** 323 * Generates a new FixPoint data value based on the unscaled 324 * value bigInt using as few bits as possible. The sign and 325 * exponent of the precision are obtained from the Precision 326 * parameter. 327 * 328 * @param bigInt Unscaled value to use for the FixPoint result 329 * @param p Used to obtain the sign and exponent of the new FixPoint value. 330 * @return FixPoint value with as few bits as necessary. 331 */ 332 public static FixPoint quantizeMinimum(BigInteger bigInt, Precision p) { 333 int sign = p.isSigned() ? 1 : 0; 334 int int_bits = bigInt.bitLength(); 335 if (int_bits == 0) { 336 int_bits++; 337 } 338 int new_bits = int_bits + sign; 339 340 Precision newPrecision = new Precision(sign, new_bits, p.getExponent()); 341 return new FixPoint(bigInt, newPrecision); 342 343 } 344 345 /** 346 * Quantize a FixPoint value using a "modulo" overflow strategy. 347 * If the unscaled integer value is outside of the dynamic range 348 * provided by the Precision constraint, modify the integer 349 * value to fit within the dynamic range using a 350 * modulo operation. Note that the Precision of the FixPoint 351 * value remains the same. 352 * 353 * @param integerValue unscaled integer value to check for overflow 354 * @param precision the precision constraint used for the overflow check 355 * @return Valid FixPoint data object 356 */ 357 public static FixPoint quantizeModulo(BigInteger integerValue, 358 Precision precision) { 359 if (!isOutOfRange(integerValue, precision)) { 360 return new FixPoint(integerValue, precision); 361 } 362 363 BigInteger moduloInteger = null; 364 365 if (!precision.isSigned()) { 366 // If the precision is unsigned, the BigInteger will 367 // be positive and the "modulo" value is the 368 // remainder of "integerValue divided by # of levels". 369 moduloInteger = integerValue 370 .remainder(precision.getNumberOfLevels()); 371 } else { 372 // If the precision is signed, we need to perform a 373 // twos complement modulo. 374 375 BigInteger minValue = precision.getMinimumUnscaledValue(); 376 moduloInteger = integerValue.subtract(minValue); 377 378 BigInteger modValue = precision.getNumberOfLevels(); 379 moduloInteger = moduloInteger.remainder(modValue); 380 381 if (integerValue.signum() < 0) { 382 moduloInteger = moduloInteger.add(modValue); 383 } 384 moduloInteger = moduloInteger.add(minValue); 385 } 386 387 return new FixPoint(moduloInteger, precision); 388 } 389 390 /** 391 * Quantize a FixPoint value using a "saturate" overflow strategy. 392 * If the unscaled integer value is outside of the dynamic range 393 * provided by the Precision constraint, modify the integer 394 * value to fit within the dynamic range by saturating the 395 * value to the maximum or minimum value supported by the 396 * Precision constraint. Note that the Precision of the FixPoint 397 * value remains the same. 398 * 399 * @param integerValue unscaled integer value to check for overflow 400 * @param precision the precision constraint used for the overflow check 401 * @return Valid FixPoint data object 402 */ 403 public static FixPoint quantizeSaturate(BigInteger integerValue, 404 Precision precision) { 405 if (isUnderflow(integerValue, precision)) { 406 return new FixPoint(precision.getMinimumUnscaledValue(), precision); 407 } 408 if (isOverflow(integerValue, precision)) { 409 return new FixPoint(precision.getMaximumUnscaledValue(), precision); 410 } 411 return new FixPoint(integerValue, precision); 412 } 413 414 /** 415 * Quantize a FixPoint value using a "to Zero" overflow strategy. 416 * If the unscaled integer value is outside of the dynamic range 417 * provided by the Precision constraint, set the integer 418 * value to zero. Note that the Precision of the FixPoint 419 * value remains the same. 420 * 421 * @param integerValue unscaled integer value to check for overflow 422 * @param precision the precision constraint used for the overflow check 423 * @return Valid FixPoint data object 424 */ 425 public static FixPoint quantizeToZero(BigInteger integerValue, 426 Precision precision) { 427 if (isOutOfRange(integerValue, precision)) { 428 return new FixPoint(BigInteger.ZERO, precision); 429 } 430 return new FixPoint(integerValue, precision); 431 } 432 433 /** Return the string representation of this overflow. 434 * @return A String. 435 */ 436 @Override 437 public String toString() { 438 return _name; 439 } 440 441 /////////////////////////////////////////////////////////////////// 442 //// public variables //// 443 // NOTE: It may seem strange that these inner classes are built this 444 // way instead of as anonymous classes... This code was copied from 445 // ptolemy.data.type.BaseType where an explanation that was valid 446 // for that usage may be found. 447 448 /** Singleton implementing Grow overflow strategy. */ 449 public static final Grow GROW = new Grow(); 450 451 /** Singleton implementing Modulo overflow strategy. */ 452 public static final Modulo MODULO = new Modulo(); 453 454 /** Singleton implementing Minimize overflow strategy. */ 455 public static final Minimize MINIMIZE = new Minimize(); 456 457 /** Singleton implementing Trap overflow strategy. */ 458 public static final Trap TRAP = new Trap(); 459 460 /** Singleton implementing Saturate overflow strategy. */ 461 public static final Saturate SATURATE = new Saturate(); 462 463 /** Singleton implementing to zero overflow strategy. */ 464 public static final ToZero TO_ZERO = new ToZero(); 465 466 // The following singleton classes are listed below (and out of 467 // alphabetic order) because they depend on the construction of 468 // other singleton objects before they can be defined. 469 470 /** Singleton implementing Saturate overflow strategy. */ 471 public static final Saturate CLIP = SATURATE; 472 473 /** Singleton implementing Grow overflow strategy. */ 474 public static final Grow GENERAL = GROW; 475 476 /** Singleton implementing Modulo overflow strategy. */ 477 public static final Modulo WRAP = MODULO; 478 479 /** Singleton implementing Trap overflow strategy. */ 480 public static final Trap THROW = TRAP; 481 482 /** The grow overflow strategy. Allow growth of value. */ 483 public static class Grow extends Overflow { 484 private Grow() { 485 super("grow"); 486 } 487 488 @Override 489 public FixPoint quantize(BigInteger integerValue, Precision precision) { 490 return quantizeGrow(integerValue, precision); 491 } 492 493 } 494 495 /** The minimize overflow strategy. */ 496 public static class Minimize extends Overflow { 497 private Minimize() { 498 super("minimize"); 499 _addOverflow(this, "shrink"); 500 } 501 502 @Override 503 public FixPoint quantize(BigInteger integerValue, Precision precision) { 504 return quantizeMinimum(integerValue, precision); 505 } 506 507 } 508 509 /** The modulo overflow strategy. */ 510 public static class Modulo extends Overflow { 511 private Modulo() { 512 super("modulo"); 513 _addOverflow(this, "wrap"); 514 } 515 516 @Override 517 public FixPoint quantize(BigInteger integerValue, Precision precision) { 518 return quantizeModulo(integerValue, precision); 519 } 520 521 } 522 523 /** The saturate overflows strategy. */ 524 public static class Saturate extends Overflow { 525 private Saturate() { 526 super("saturate"); 527 _addOverflow(this, "clip"); 528 } 529 530 @Override 531 public BigInteger minusInfinity(Quantization quant) { 532 return quant.getMinimumUnscaledValue(); 533 } 534 535 @Override 536 public BigInteger plusInfinity(Quantization quant) { 537 return quant.getMaximumUnscaledValue(); 538 } 539 540 @Override 541 public FixPoint quantize(BigInteger integerValue, Precision precision) { 542 return quantizeSaturate(integerValue, precision); 543 } 544 } 545 546 /** The overflow to zero strategy. */ 547 public static class ToZero extends Overflow { 548 private ToZero() { 549 super("to_zero"); 550 _addOverflow(this, "overflow_to_zero"); // For compatibility. 551 } 552 553 @Override 554 public BigInteger minusInfinity(Quantization quant) { 555 return BigInteger.ZERO; 556 } 557 558 @Override 559 public BigInteger plusInfinity(Quantization quant) { 560 return BigInteger.ZERO; 561 } 562 563 @Override 564 public FixPoint quantize(BigInteger integerValue, Precision precision) { 565 return quantizeToZero(integerValue, precision); 566 } 567 } 568 569 /** The trap overflows strategy. */ 570 public static class Trap extends Overflow { 571 private Trap() { 572 super("trap"); 573 _addOverflow(this, "throw"); 574 } 575 576 @Override 577 public FixPoint quantize(BigInteger integerValue, Precision precision) { 578 if (isUnderflow(integerValue, precision)) { 579 throw new ArithmeticException("Minimum overflow threshold of " 580 + precision.getMinimumUnscaledValue() 581 + " exceeded with value " + integerValue); 582 } 583 if (isOverflow(integerValue, precision)) { 584 throw new ArithmeticException("Maximum overflow threshold of " 585 + precision.getMaximumUnscaledValue() 586 + " exceeded with value " + integerValue); 587 } 588 return new FixPoint(integerValue, precision); 589 } 590 } 591 592 /////////////////////////////////////////////////////////////////// 593 //// protected constructor //// 594 595 /** Construct an Overflow object with the given String name. 596 * This name is used for finding an Overflow object at a later 597 * time (@see #forName(String)). This constructor 598 * is protected to make a type safe enumeration. 599 * 600 * @param name The String name to give this Overflow strategy. 601 * 602 */ 603 protected Overflow(String name) { 604 _name = name; 605 _addOverflow(this, name); 606 } 607 608 // The constructor is protected to make a type safe enumeration. 609 610 /////////////////////////////////////////////////////////////////// 611 //// package private method //// 612 // Add entries in this class to index the given name to 613 // the given overflow type. 614 static void _addOverflow(Overflow type, String name) { 615 // Because the private variables are below the public variables 616 // that call this initializer, 617 // it doesn't work to initialize this statically. 618 if (_nameToOverflow == null) { 619 _nameToOverflow = new HashMap(); 620 } 621 622 _nameToOverflow.put(name, type); 623 } 624 625 /////////////////////////////////////////////////////////////////// 626 //// private variables //// 627 private String _name; 628 629 // A map from overflow type name to the overflow type for all 630 // overflow types. 631 private static volatile Map _nameToOverflow; 632 633}