001/* A FixPoint data type. 002 003 Copyright (c) 1998-2018 The Regents of the University of California. 004 All rights reserved. 005 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.math; 030 031import java.math.BigDecimal; 032import java.math.BigInteger; 033 034/////////////////////////////////////////////////////////////////// 035//// FixPoint 036 037/** 038 The FixPoint class provides a fixed point data type and a set of functions 039 that operate on and return fixed point data. An instance of the class 040 is immutable, meaning that its value is set in the constructor and 041 cannot then be modified. This is similar to the Java built-in classes 042 like Double, Integer, etc. 043 <p> 044 The FixPoint class represents signed numbers in a two's-complement 045 format or unsigned numbers in a binary format with unlimited dynamic 046 range and a resolution defined by a finite number of fractional bits. 047 The precision is defined by the 048 {@link ptolemy.math.Precision Precision} class. 049 <p> 050 Because a fixed point data type uses a finite number of bits to 051 represent a value, a real value is converted to a number that 052 can be expressed with a given precision of the fixed point, thereby 053 introducing a quantization error. 054 055 The overflow and rounding strategies 056 used for this quantization are defined by an instance of 057 the {@link ptolemy.math.Quantization Quantization} class. 058 <p> 059 The design of the FixPoint class complies with a philosophy that all 060 operators work losslessly, i.e. the fractional precision of the result 061 is determined such there is no loss of precision. To insure lossless 062 operations, the resulting Precision of these operators will expand as 063 necessary. Subsequent results can be quantized as necessary. 064 <p> 065 Violations of the loss-less philosophy occur during construction, division 066 and conversion to floating point. During construction from floating point 067 values, the nearest fixed point representation is created. The preferred 068 divide operator provides for explicit specification of the quantization. 069 A deprecated divide operator guesses at the result precision. 070 Conversion to floating point is limited by the available floating point 071 accuracy. 072 <p> 073 The FixPoint implementation uses the Java class BigInteger to represent the 074 finite value and so this implementation is truly platform independent. 075 Note that the FixPoint does not put any restrictions on the maximum number 076 of bits in the representation of a value. 077 078 @author Bart Kienhuis, Ed Willink, Contributor: Edward A. Lee, Mike Wirthlin 079 @version $Id$ 080 @since Ptolemy II 0.4, rewritten for Ptolemy II 2.2 081 @Pt.ProposedRating Red (Ed.Willink) 082 @Pt.AcceptedRating Red 083 @see ptolemy.math.Precision 084 @see ptolemy.math.Quantization 085 */ 086public class FixPoint implements Cloneable { 087 088 /** Construct a FixPoint by converting a bigDecimal to comply 089 * with a quantization specification. 090 * 091 * @param bigDecimal The floating point value. 092 * @param quant The quantization specification. 093 */ 094 public FixPoint(BigDecimal bigDecimal, Quantization quant) { 095 _initFromBigDecimal(bigDecimal, quant); 096 } 097 098 /** Construct a new FixPoint object by requantizing the 099 * given FixPoint object with a new quantization specification. 100 * 101 * TODO: This isn't the most efficient way of requantizing 102 * a value. Need to look into more efficient techniques for 103 * doing simple requantizations rather than converting into 104 * a BigDecimal. Proposal: 105 * - Create methods in Rounding to support Rounding 106 * of "shifted" BigInteger values 107 * - Perform rounding using shifting rather than 108 * conversion to BigDecimal 109 * 110 * @param fix The existing FixPoint value 111 * @param quant The quantization specification. 112 */ 113 public FixPoint(FixPoint fix, Quantization quant) { 114 _initFromBigDecimal(fix.bigDecimalValue(), quant); 115 } 116 117 /** Construct a FixPoint from a double. 118 * Perform the conversion using the given 119 * quantization specification. 120 * 121 * @param doubleValue The floating point value. 122 * @param quant The quantization specification. 123 * @exception IllegalArgumentException If the doubleValue is equal 124 * to Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 125 * or Double.NaN. 126 */ 127 public FixPoint(double doubleValue, Quantization quant) { 128 try { 129 BigDecimal bigDecimal = new BigDecimal(doubleValue); 130 _initFromBigDecimal(bigDecimal, quant); 131 } catch (NumberFormatException e) { 132 throw new IllegalArgumentException( 133 "NumberFormatException " + "while converting \"" 134 + doubleValue + "\" to a FixPoint."); 135 } 136 } 137 138 /** Construct a FixPoint from an integer. 139 * Perform the conversion using the given quantization 140 * specification. During conversion, overflow handling 141 * may result in a lossy conversion. 142 * 143 * @param intValue The integer value. 144 * @param quant The quantization specification. 145 */ 146 public FixPoint(int intValue, Quantization quant) { 147 BigInteger bigInt = new BigInteger(Integer.toString(intValue)); 148 _initFromBigInteger(bigInt, quant); 149 } 150 151 /** Construct a FixPoint from an integer. 152 * This is a loss-less conversion with a precision having 153 * as few bits as possible to represent the value and 154 * represented as a signed number. 155 * 156 * @param intValue The integer value. 157 */ 158 public FixPoint(int intValue) { 159 this(intValue, true); 160 } 161 162 /** Construct a FixPoint from an integer. 163 * This is a loss-less conversion with a precision having 164 * as few bits as possible to represent the value and the 165 * signed determined by the signed parameter. 166 * 167 * @param intValue The integer value. 168 * @param signed if true, represent value as a signed number; 169 * otherwise represent value as an unsigned value. 170 */ 171 public FixPoint(int intValue, boolean signed) { 172 // Create a new integer FixPoint value with 173 // a small precision but with a "grow" overflow strategy. 174 this(intValue, 175 new FixPointQuantization( 176 new Precision(signed ? 1 : 0, (signed ? 1 : 0) + 1, 0), 177 Overflow.GROW, Rounding.HALF_EVEN)); 178 } 179 180 /** Construct a FixPoint by converting the BigDecimal interpretation of 181 * a string to comply with a quantization specification. 182 * 183 * @param string A string representation of the floating point value. 184 * @param quant The quantization specification. 185 * @exception IllegalArgumentException If string is not a valid 186 * representation of a BigDecimal. 187 */ 188 public FixPoint(String string, Quantization quant) { 189 190 try { 191 BigDecimal bigDecimal = new BigDecimal(string); 192 _initFromBigDecimal(bigDecimal, quant); 193 } catch (NumberFormatException e) { 194 throw new IllegalArgumentException("NumberFormatException " 195 + "while converting \"" + string + "\" to a FixPoint."); 196 } 197 } 198 199 /////////////////////////////////////////////////////////////////// 200 //// public methods //// 201 202 /** Determines the Precision of an add operation between two 203 * FixPoint values. 204 * 205 * The Precision of the result of an add between two FixPoint 206 * values is the Precision union of the two arguments plus 207 * one (to allow for bit growth). 208 */ 209 public static Precision addPrecision(Precision leftArgument, 210 Precision rightArgument) { 211 Precision union = Precision.union(leftArgument, rightArgument); 212 Precision newPrecision = new Precision(union.getSign(), 213 union.getNumberOfBits() + 1, union.getExponent()); 214 return newPrecision; 215 } 216 217 /** Determines the Precision of an subtract operation between two 218 * FixPoint values. 219 * 220 * The subtract precision will increment by one and always 221 * be signed. 222 */ 223 public static Precision subtractPrecision(Precision leftArgument, 224 Precision rightArgument) { 225 Precision union = Precision.union(leftArgument, rightArgument); 226 int length = union.getNumberOfBits() + 1; 227 Precision newPrecision = new Precision(1, length, union.getExponent()); 228 return newPrecision; 229 } 230 231 /** Determines the Precision of an multiply operation between 232 * two FixPoint values. 233 * 234 * The resulting Precision of a multiply between two FixPoint 235 * arguments is as follows: the integer location is the sum 236 * of the integer locations of the two arguments and the 237 * fractional location is the sum of the fractional locations 238 * of the two arguments. 239 */ 240 public static Precision multiplyPrecision(Precision leftArgument, 241 Precision rightArgument) { 242 int sign = leftArgument.getSign() == 1 || rightArgument.getSign() == 1 243 ? 1 244 : 0; 245 int fractionBits = leftArgument.getFractionBitLength() 246 + rightArgument.getFractionBitLength(); 247 int integerBits = leftArgument.getIntegerBitLength() 248 + rightArgument.getIntegerBitLength(); 249 Precision newPrecision = new Precision(sign, fractionBits + integerBits, 250 -fractionBits); 251 return newPrecision; 252 } 253 254 /** Determines the Precision of a divide operation between 255 * two FixPoint values. 256 * 257 * It is not possible to represent the result of an arbitrary 258 * divide with a finite precision. As such, this precision 259 * conversion rule is lossless. The rule for divide is as 260 * follows: 261 * - Integer part = left integer bits + right fraction bits + sign 262 * - Fraction part = left fractional bits + right integer bits + 1 - sign 263 */ 264 public static Precision dividePrecision(Precision leftArgument, 265 Precision rightArgument) { 266 int sign = leftArgument.getSign() == 1 || rightArgument.getSign() == 1 267 ? 1 268 : 0; 269 int integerBits = leftArgument.getIntegerBitLength() 270 + rightArgument.getFractionBitLength() + sign; 271 int fractionBits = leftArgument.getFractionBitLength() 272 + rightArgument.getIntegerBitLength() + 1 - sign; 273 Precision newPrecision = new Precision(sign, 274 sign + fractionBits + integerBits, -fractionBits); 275 return newPrecision; 276 } 277 278 /** Return a FixPoint with a value equal to the absolute 279 * value of this FixPoint. The operation is lossless and 280 * the Precision of the result is the same Precision as 281 * this object. 282 * 283 * @return A non-negative fixed point. 284 */ 285 public FixPoint abs() { 286 return new FixPoint(_value.abs(), _precision); 287 } 288 289 /** Return a FixPoint with a value equal to the sum of this 290 * FixPoint and the argument. The operation is lossless and 291 * will "expand" the Precision of the resulting FixPoint 292 * value to include the full precision of the result. 293 * 294 * This operation will operate on either signed or unsigned 295 * fixed values. If both operands of an operation are unsigned, 296 * the result will be unsigned. If either of the operations are 297 * signed, the result will be signed. 298 * 299 * @param arg The FixPoint addend. 300 * @return The FixPoint sum. 301 */ 302 public FixPoint add(FixPoint arg) { 303 304 // Align the two arguments 305 int minExponent = Math.min(_precision.getExponent(), 306 arg._precision.getExponent()); 307 BigInteger thisValue = _alignToExponent(minExponent); 308 BigInteger thatValue = arg._alignToExponent(minExponent); 309 310 // Perform the addition 311 BigInteger newValue = thisValue.add(thatValue); 312 313 // Create new precision 314 /* 315 int sign = _determineSign(_precision, arg._precision); 316 int new_bits = newValue.bitLength() + sign; 317 int max_bits = Math.max(_precision.getNumberOfBits(), arg._precision 318 .getNumberOfBits()); 319 int bits = (new_bits > max_bits ? new_bits : max_bits); 320 321 Precision newPrecision = new Precision(sign, bits, minExponent); 322 */ 323 Precision newPrecision = addPrecision(_precision, arg._precision); 324 return new FixPoint(newValue, newPrecision); 325 } 326 327 /** Return a FixPoint with a value equal to the sum of this 328 * FixPoint and the argument. The precision of this operation 329 * is set by the Quantization parameter and the result of the 330 * operation may be lossy as dictated by the desired quantization. 331 * <p> 332 * 333 * @param arg The FixPoint addend. 334 * @param quant The quantization specification. 335 * @return The FixPoint sum. 336 */ 337 public FixPoint add(FixPoint arg, Quantization quant) { 338 return add(arg).quantize(quant); 339 } 340 341 /** Return the value of this FixPoint as a BigDecimal number. 342 * This is lossless, since the scale of the BigDecimal is set 343 * to the number of fractional bits. 344 * 345 * @return The BigDecimal value of this FixPoint. 346 */ 347 public BigDecimal bigDecimalValue() { 348 return Precision.shiftBigDecimal(new BigDecimal(_value), 349 _precision.getExponent()); 350 } 351 352 /** Return this, that is, return the reference to this object. 353 * @return This FixPoint. 354 */ 355 @Override 356 public Object clone() { 357 // FIXME: Note that we do not call super.clone() here. Is that right? 358 return this; 359 } 360 361 /** Return a FixPoint with a value equal to the division of 362 * this FixPoint by the argument. The operation is <b>not</b> 363 * lossless. 364 * <p> 365 * 366 * @param arg The FixPoint.divisor. 367 * @return The FixPoint quotient. 368 * @exception IllegalArgumentException If division by zero and 369 * infinity not quantizable. 370 */ 371 public FixPoint divide(FixPoint arg) throws IllegalArgumentException { 372 373 /* 374 int minExponent = Math.min(_precision.getExponent(), arg._precision 375 .getExponent()); 376 int sign = _determineSign(_precision, arg._precision); 377 int maxLength = Math.max(_precision.getNumberOfBits(), arg._precision 378 .getNumberOfBits()); 379 Precision netPrecision = new Precision(sign, maxLength, minExponent); 380 */ 381 Precision newPrecision = dividePrecision(this._precision, 382 arg._precision); 383 Quantization netQuantization = new FixPointQuantization(newPrecision, 384 Overflow.TRAP, Rounding.NEAREST); 385 return divide(arg, netQuantization); 386 } 387 388 /** Return a FixPoint equal to the division of this FixPoint by the 389 * argument, after application of a quantization specification to 390 * the result. The operation is <b>not</b> lossless. 391 * <p> 392 * Division by zero results in a value of plus or minus infinity, 393 * which throws an exception if the overflow strategy defined by 394 * the quantization specification returns 395 * null for plusInfinity or minusInfinity. 396 * 397 * @param arg The FixPoint.divisor. 398 * @param quant The quantization specification. 399 * @return The FixPoint quotient. 400 * @exception IllegalArgumentException If division by zero. 401 */ 402 public FixPoint divide(FixPoint arg, Quantization quant) 403 throws IllegalArgumentException { 404 405 try { 406 407 BigDecimal numerator = new BigDecimal(this._value); 408 BigDecimal denominator = new BigDecimal(arg._value); 409 410 // Perform the division using the BigDecimal.divide 411 // method. When calling this method, we need to know 412 // how many bits to the right of the decimal place 413 // to save (there can be an uncountable number of digits 414 // to the right after the division). This is specified by 415 // the base 10 "scale" value. We will set this base-10 416 // scale value to the desired base 2 scale value 417 // (i.e. the -exponent) and add one to give us an 418 // extra digit. 419 int resultExp = quant.getPrecision().getExponent(); 420 int scale = resultExp < 0 ? -resultExp : 0; 421 scale++; 422 BigDecimal result = numerator.divide(denominator, scale, 423 BigDecimal.ROUND_HALF_EVEN); 424 425 int result_shift = this._precision.getExponent() 426 - arg.getPrecision().getExponent(); 427 result = Precision.shiftBigDecimal(result, result_shift); 428 429 return new FixPoint(result, quant); 430 431 } catch (ArithmeticException e) { 432 Overflow anOverflow = quant.getOverflow(); 433 BigInteger infinity = _value.signum() >= 0 434 ? anOverflow.plusInfinity(quant) 435 : anOverflow.minusInfinity(quant); 436 437 if (infinity != null) { 438 return new FixPoint(infinity, quant.getPrecision()); 439 } 440 441 throw new IllegalArgumentException( 442 "ArithmeticException " + "while dividing " + toString() 443 + " by " + arg.toString() + '.'); 444 } 445 } 446 447 /** Return the value of this FixPoint as a double. This 448 * is not necessarily lossless, since the precision of the fixed point 449 * number may exceed that of the double. 450 * @return The double value of this FixPoint. 451 */ 452 public double doubleValue() { 453 return _value.doubleValue() * Math.pow(2.0, _precision.getExponent()); 454 } 455 456 /** Return true if this FixPoint is equal to the argument. Two 457 * FixPoints are considered equal when the two values are 458 * precisely the same. The two FixPoints need not therefore have 459 * the same number of fraction bits, but any additional fractional 460 * bits in one value must be zero in the other. 461 * 462 * @param arg The FixPoint object to use for equality 463 * checking. 464 * @return True if the FixPoints are equal; false otherwise. 465 */ 466 @Override 467 public boolean equals(Object arg) { 468 if (arg instanceof FixPoint) { 469 int exponentBits = Math.min(_precision.getExponent(), 470 ((FixPoint) arg)._precision.getExponent()); 471 BigInteger thisValue = _alignToExponent(exponentBits); 472 BigInteger thatValue = ((FixPoint) arg) 473 ._alignToExponent(exponentBits); 474 return thisValue.equals(thatValue); 475 } 476 return false; 477 } 478 479 /** Get the Error condition from the FixValue. 480 * @return The error condition of the FixValue. 481 * @deprecated Overflow and rounding status no longer form part of 482 * the functionality. Use an overflow and rounding mode that gives the 483 * required behaviour or use Overflow.TRAP and/or Rounding.UNNECESSARY 484 * to throw exceptions if external interaction is required. 485 */ 486 @Deprecated 487 public Error getError() { 488 return _error; 489 } 490 491 /** Return a precision to represent this number. This is constructed 492 * from the necessary fraction precision and the integer precision 493 * annotation. 494 * @return The Precision of this number. 495 */ 496 public Precision getPrecision() { 497 return _precision; 498 } 499 500 /** Return the unscaled BigInteger value used to represent this 501 * FixPoint value. 502 * 503 * @return The BigInteger unscaled value of this number. 504 */ 505 public BigInteger getUnscaledValue() { 506 return _value; 507 } 508 509 /** Return a hash code value for this value. This method returns the 510 * low order 32 bits of the integer representation. 511 * @return A hash code value for this value. 512 */ 513 @Override 514 public int hashCode() { 515 return _value.intValue(); 516 } 517 518 /** Return a new FixPoint value that has the same value as this 519 * FixPoint value but with the minimum quantization necessary for 520 * representing the value. 521 * 522 * The first step of this requantization is to check for 523 * "zero" bits at the LSB positions of the unscaled value. 524 * The value is shifted until the first "1" is found and 525 * the exponent is adjusted. Next, the length of the unscaled 526 * value is examined and the precision is set to the minimum 527 * length possible to represent the value. 528 * 529 * @return The minimum quantize FixPoint value. 530 */ 531 public FixPoint minimumQuantization() { 532 533 int new_sign = _precision.getSign(); 534 535 // determine wasted bits in LSB locations & update exponent 536 int shiftVal = _value.getLowestSetBit(); 537 BigInteger newVal = _value.shiftRight(shiftVal); 538 int new_exponent = _precision.getExponent() + shiftVal; 539 540 // determine minimum length of "new value" 541 int new_bitlength = newVal.bitLength() + new_sign; 542 543 Precision newPrecision = new Precision(new_sign, new_bitlength, 544 new_exponent); 545 return new FixPoint(newVal, newPrecision); 546 } 547 548 /** Return a FixPoint with a value equal to the product of this 549 * FixPoint and the argument. The operation is lossless and 550 * will "expand" the Precision of the resulting FixPoint 551 * value to include the full precision of the result. 552 * 553 * This operation will operate on either signed or unsigned 554 * fixed values. If both operands of an operation are unsigned, 555 * the result will be unsigned. If either of the operations are 556 * signed, the result will be signed. 557 * 558 * @param arg The FixPoint multiplier. 559 * @return The FixPoint product. 560 */ 561 public FixPoint multiply(FixPoint arg) { 562 563 // 1. Create FixPoint value with "worst case" precision 564 BigInteger newValue = _value.multiply(arg._value); 565 566 /* 567 int new_sign = _determineSign(_precision, arg._precision); 568 int new_exponent = _precision.getExponent() 569 + arg._precision.getExponent(); 570 Precision worstCasePrecision = new Precision(new_sign, new_sign 571 + newValue.bitLength(), new_exponent); 572 FixPoint newVal = new FixPoint(newValue, worstCasePrecision); 573 574 // 2. Requantize the value with the minimum quantization necessary 575 newVal = newVal.minimumQuantization(); 576 577 // 3. Determine "Growth" precision for result. This will be the 578 // "maximium" of the precision of the arguments and the result. 579 Precision newPrecision = 580 Precision.union(_precision, arg._precision); 581 newPrecision = Precision.union(newPrecision, newVal._precision); 582 */ 583 584 Precision newPrecision = multiplyPrecision(_precision, arg._precision); 585 FixPoint newVal = new FixPoint(newValue, newPrecision); 586 587 // 4. Requantize the result with the new precision (this 588 // precision should be adequate and will not cause overflow 589 // or rounding. 590 FixPoint fp = new FixPoint(newVal, new FixPointQuantization( 591 newPrecision, Overflow.GENERAL, Rounding.GENERAL)); 592 return fp; 593 } 594 595 /** Return a FixPoint with a value equal to the product of this 596 * FixPoint and the argument. The precision of this operation 597 * is set by the Quantization parameter and the result of the 598 * operation may be lossy as dictated by the desired quantization. 599 * <p> 600 * 601 * @param arg The FixPoint multiplicand. 602 * @param quant The quantization specification. 603 * @return The FixPoint product. 604 */ 605 public FixPoint multiply(FixPoint arg, Quantization quant) { 606 return multiply(arg).quantize(quant); 607 } 608 609 /** Print useful debug information about the FixPoint to standard 610 * out. This is used for debugging. 611 */ 612 public void printFix() { 613 System.out.println(" unscale Value (2) " + _value.toString(2)); 614 System.out.println(" unscaled Value (10) " + _value.toString(10)); 615 System.out.println(" scale Value (10) " + doubleValue() + " Precision: " 616 + getPrecision().toString()); 617 System.out.println(" BitCount: " + _value.bitCount()); 618 System.out.println(" BitLength " + _value.bitLength()); 619 620 BigInteger j = _value.abs(); 621 System.out.println(" ABS value " + j.toString(2)); 622 System.out.println(" ABS bit count: " + j.bitCount()); 623 System.out.println(" ABD bitLength: " + j.bitLength()); 624 System.out.println( 625 " Max value: " + getPrecision().findMaximum().doubleValue()); 626 System.out.println( 627 " Min value: " + getPrecision().findMinimum().doubleValue()); 628 } 629 630 /** Return the value after conversion to comply with a 631 * quantization specification. This method calls 632 * {@link #FixPoint(FixPoint, Quantization)}. 633 * 634 * @param quant The quantization constraints. 635 * @return The bounded integer value. 636 */ 637 public FixPoint quantize(Quantization quant) { 638 return new FixPoint(this, quant); 639 } 640 641 /** Return a FixPoint with a value equal to the difference 642 * between this FixPoint and the argument. The operation is 643 * lossless and will "expand" the Precision of the resulting 644 * FixPoint value to include the full precision of the result. 645 * 646 * This operation will operate on either signed or unsigned 647 * fixed values. If either of the operations are 648 * signed, the result will be signed. If both operands are 649 * unsigned and the result is positive, an unsigned value 650 * will be produced. If both operands are unsigned and the 651 * result is negative, a signed value will be generated. 652 * 653 * @param arg The FixPoint subtrahend. 654 * @return The FixPoint difference. 655 */ 656 public FixPoint subtract(FixPoint arg) { 657 658 // Align the two arguments 659 int minExponent = Math.min(_precision.getExponent(), 660 arg._precision.getExponent()); 661 BigInteger thisValue = _alignToExponent(minExponent); 662 BigInteger thatValue = arg._alignToExponent(minExponent); 663 664 // Perform the subtraction 665 BigInteger newValue = thisValue.subtract(thatValue); 666 667 /* 668 // Create new precision 669 int sign = _determineSign(_precision, arg._precision); 670 // If the sign of the subtract is negative and both arguments 671 // were unsigned, make the result signed. 672 if (sign == 0 && newValue.signum() == -1) 673 sign = 1; 674 675 int new_bits = newValue.bitLength() + sign; 676 int max_bits = Math.max(_precision.getNumberOfBits(), arg._precision 677 .getNumberOfBits()); 678 int bits = (new_bits > max_bits ? new_bits : max_bits); 679 680 Precision newPrecision = new Precision(sign, bits, minExponent); 681 */ 682 Precision newPrecision = subtractPrecision(_precision, arg._precision); 683 return new FixPoint(newValue, newPrecision); 684 } 685 686 /** Return a FixPoint with a value equal to the difference of this 687 * FixPoint and the argument. The precision of this operation 688 * is set by the Quantization parameter and the result of the 689 * operation may be lossy as dictated by the desired quantization. 690 * <p> 691 * 692 * @param arg The FixPoint addend. 693 * @param quant The quantization specification. 694 * @return The FixPoint sum. 695 */ 696 public FixPoint subtract(FixPoint arg, Quantization quant) { 697 return subtract(arg).quantize(quant); 698 } 699 700 /** Return a bit string representation of this number. 701 * The string takes the form "<i>sign integerBits . fractionBits</i>", 702 * where <i>sign</i> is - or nothing, <i>integerBits</i> 703 * and <i>fractionBits</i> are 704 * each a sequence of "0" and "1". <i>integerBits</i> comprises no 705 * leading zeroes. <i>fractionBits</i> has exactly one digit per bit. 706 * If the fixed point number has zero or negative number of fraction 707 * bits, the dot is omitted. 708 * @return A binary string representation of the value. 709 */ 710 public String toBitString() { 711 712 // This simple line used to preserve as much of code as possible 713 int _frac_bits = -_precision.getExponent(); 714 715 BigInteger integerPart = _value.shiftRight(_frac_bits); 716 StringBuffer ln = new StringBuffer(integerPart.toString(2)); 717 718 if (_frac_bits > 0) { 719 // The the toString(2) method of BigInteger removes the most 720 // significant bits that are zeros, this method recreates 721 // these zeroes to get the correct representation of the 722 // fractional part. 723 724 BigInteger fractionModulus = BigInteger.ZERO.setBit(_frac_bits); 725 BigInteger fractionMask = fractionModulus.subtract(BigInteger.ONE); 726 BigInteger fractionPart = _value.and(fractionMask); 727 int minFracBits = fractionPart.bitLength(); 728 int extraLeadingFracBits = _frac_bits - minFracBits; 729 ln.append("."); 730 731 // Append the zeros 732 for (int i = 0; i < extraLeadingFracBits; i++) { 733 ln.append("0"); 734 } 735 736 if (minFracBits > 0) { 737 ln.append(fractionPart.toString(2)); 738 } 739 } 740 741 return ln.toString(); 742 } 743 744 /** Return a string representation of this number. 745 * This is calculated by first converting the number to a BigDecimal, 746 * and then returning its string representation. In order to avoid 747 * loss there may be as many decimal digits following the decimal 748 * point as there fractional bits in this FixPoint. 749 * @return A decimal string representation of the value. 750 */ 751 @Override 752 public String toString() { 753 BigDecimal decimal = bigDecimalValue(); 754 String bigString = decimal.toString(); 755 756 if (bigString.indexOf('.') < 0) { 757 if (bigString.indexOf('E') < 0) { 758 return bigString; 759 } else { 760 // Java 1.5 release notes: 761 // "The DecimalFormat class has been enhanced 762 // to format and parse BigDecimal and BigInteger 763 // values without loss of precision. Formatting of 764 // such values is enhanced automatically; parsing into 765 // BigDecimal needs to be enabled using the 766 // setParseBigDecimal method." 767 // 768 // Formatter "An interpreter for printf-style format 769 // strings, the Formatter class provides support for 770 // layout justification and alignment, common formats 771 // for numeric, string, and date/time data, and 772 // locale-specific output. Common Java types such as 773 // byte, java.math.BigDecimal , and java.util.Calendar 774 // are supported. Limited formatting customization for 775 // arbitrary user types is provided through the 776 // java.util.Formattable interface." 777 // As a result, sometimes we get 0E-12 or 0E-8 instead 778 // of 0.0. 779 if (bigString.startsWith("0E-")) { 780 // FIXME: This is a bit of a hack, we could be more 781 // robust and use regular expressions. 782 return "0.0"; 783 } else { 784 // This is probably an error, but give the user 785 // a chance. 786 return bigString; 787 } 788 } 789 } 790 791 // In order to preserve backward compatibility 792 // we need to strip redundant trailing 0's. 793 int i = bigString.length() - 1; 794 795 while (bigString.charAt(i) == '0' && bigString.charAt(i - 1) != '.') { 796 --i; 797 } 798 799 return bigString.substring(0, i + 1); 800 } 801 802 /** Return a string representation of this number along with 803 * the Precision of the number. 804 * 805 * @return A decimal string representation of the value and its 806 * precision. 807 */ 808 public String toStringPrecision() { 809 return toString() + _precision.toString(); 810 } 811 812 /** Return a string representation of this number along with 813 * the unscaled value and Precision of the number. 814 * 815 * @return A decimal string representation of the value and its 816 * precision. 817 */ 818 public String toStringValuePrecision() { 819 return toString() + " [" + _precision.toString() + "=" + _value + "]"; 820 } 821 822 /////////////////////////////////////////////////////////////////// 823 //// package methods //// 824 825 /** Construct a FixPoint from an unscaled integerValue that 826 * with a given Precision constraint. This method will 827 * throw an exception if the precision is not sufficient to 828 * represent the given integer value. 829 * 830 * @param unscaledIntegerValue The integer value of the scaled 831 * floating point value. 832 * @param precision The precision to represent the new unscaled value. 833 * @exception ArithmeticException when precision is not sufficient 834 * to represent integerValue. 835 * 836 * Note that this is package scope 837 */ 838 FixPoint(BigInteger unscaledIntegerValue, Precision precision) { 839 if (Overflow.isOutOfRange(unscaledIntegerValue, precision)) { 840 throw new ArithmeticException("Precision " + precision 841 + " not sufficient to represent " + unscaledIntegerValue); 842 } 843 _precision = precision; 844 _value = unscaledIntegerValue; 845 } 846 847 /////////////////////////////////////////////////////////////////// 848 //// private constructor //// 849 850 /////////////////////////////////////////////////////////////////// 851 //// private methods //// 852 853 /** Return the BigInteger whose fractional part is aligned with the 854 * provided precision. This never involves rounding, but only 855 * padding the fractional part with zeros 856 * @param exponent The precision with which to align 857 * @return A BigInteger with aligned precision 858 */ 859 private BigInteger _alignToExponent(int exponent) { 860 861 int exponentChange = exponent - _precision.getExponent(); 862 863 if (exponentChange < 0) { 864 return _value.shiftLeft(-exponentChange); 865 } else { // This is a private method so we know that extraBits is +ve 866 return _value; 867 } 868 } 869 870 /** Initialize the _value and _precision of this object from 871 * a BigDecimal value. 872 * 873 * There are three steps involved with converting a BigDecimal 874 * value into a FixPoint value. The first step is to 875 * shift the BigDecimal value in a way that preserves 876 * all of the desired precision. Next, the shifted 877 * BigDecimal value is rounded using the appropriate 878 * rounding mode. The third and final step 879 * is to apply the appropriate Overflow strategy to 880 * the resulting BigInteger object. 881 * 882 * After completing this method, the _value and _precision 883 * are set. 884 * 885 * @param bigDecimal The floating point value. 886 * @param quant The quantization specification. 887 */ 888 private void _initFromBigDecimal(BigDecimal bigDecimal, 889 Quantization quant) { 890 891 // Step 1: - Check to see if the number is negative and the 892 // precision is unsigned. If so, throw an exception. 893 if (!quant.getPrecision().isSigned() && bigDecimal.signum() < 0) { 894 throw new ArithmeticException("Attempting to create a unsigned" 895 + " FixPoint from a negative double:" + bigDecimal); 896 } 897 898 // Step 2: - Handle the right side (lsb) of the BigDecimal value 899 // by shifting. 900 // If the exponent is less than zero, shift the result left. 901 // If the exponent is greater than zero, shift the result right. 902 BigDecimal shiftedDecimal = Precision.shiftBigDecimal(bigDecimal, 903 -quant.getPrecision().getExponent()); 904 905 // Step 3: Round the shifted decimal value 906 BigInteger roundedInteger = quant.getRounding().round(shiftedDecimal); 907 908 // Step 4: Handle any overflow associated with this precision 909 FixPoint newFix = quant.getOverflow().quantize(roundedInteger, 910 quant.getPrecision()); 911 912 this._value = newFix._value; 913 this._precision = newFix._precision; 914 } 915 916 /** Initialize the _value and _precision of this object from 917 * a BigInteger value. 918 * 919 * The primary step in this method is to perform the 920 * "overflow" check and requantization. The BigInteger 921 * will be quantized using the overflow policy provided 922 * by the quantization parameter. See 923 * {@link Overflow#quantize(BigInteger, Precision)}. 924 * 925 * After completing this method, the _value and _precision 926 * are set. 927 * 928 * @param bigInteger The integer value. 929 * @param quant The quantization specification. 930 */ 931 private void _initFromBigInteger(BigInteger bigInteger, 932 Quantization quant) { 933 934 // Step 1: - Check to see if the number is negative and the 935 // precision is unsigned. If so, throw an exception. 936 if (!quant.getPrecision().isSigned() && bigInteger.signum() < 0) { 937 throw new ArithmeticException("Attempting to create a unsigned" 938 + " FixPoint from a negative integer:" + bigInteger); 939 } 940 941 // Step 2: Shift the BigInteger value to match the desired 942 // Precision. There are two cases. If the exponent 943 // is greater than 0, then the integer will be 944 // shifted "right" and rounding may occur. In this 945 // case, call _initFromBigInteger to take advantage 946 // of the rounding in that method. If the exponent 947 // is less than 0, the integer must be shifted 948 // left with zeros in the lsbs. This is handled here. 949 int desiredExponent = quant.getPrecision().getExponent(); 950 if (desiredExponent > 0) { 951 // FIXME: It is possible that the BigInteger has all zeros 952 // in the least significant bits that are shifted away. To 953 // improve performance, check to see if this is a case and 954 // perform the shift locally rather than going through the 955 // BigDecimal code. 956 _initFromBigDecimal(new BigDecimal(bigInteger), quant); 957 return; 958 } else if (desiredExponent < 0) { 959 bigInteger = bigInteger.shiftLeft(-desiredExponent); 960 } 961 962 // Step 3: Handle any overflow associated with this precision 963 FixPoint newFix = quant.getOverflow().quantize(bigInteger, 964 quant.getPrecision()); 965 966 this._value = newFix._value; 967 this._precision = newFix._precision; 968 } 969 970 /////////////////////////////////////////////////////////////////// 971 //// private variables //// 972 973 /** The BigInteger comprising the logical floating point value 974 * multiplied by 2^exponent. 975 */ 976 private BigInteger _value; 977 978 /** The Precision of the given FixPoint value. **/ 979 private Precision _precision; 980 981 /** The obsolete error condition of the FixValue */ 982 private Error _error = new Error(); 983 984 /////////////////////////////////////////////////////////////////// 985 //// inner classes //// 986 987 /** An instance of this class is used preserve backwards interface 988 * compatibility. It contains a description that now states that 989 * there is no tracking of applied overflow or rounding. 990 */ 991 public static class Error { 992 // The only constructor is private so that this class cannot 993 // be instantiated. 994 private Error() { 995 } 996 997 /** Get a description of the Error. 998 * @return A description of the Error. 999 * @deprecated This functionality is obsolete. 1000 */ 1001 @Deprecated 1002 public String getDescription() { 1003 return " Overflow status is no longer tracked."; 1004 } 1005 } 1006}