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}