001/* A collection of methods for creating fixed point values.
002
003 Copyright (c) 1998-2014 The Regents of the University of California
004 and Research in Motion Limited.  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 OR RESEARCH IN MOTION
013 LIMITED BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
014 INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
015 SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
016 HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED
019 SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
022 THE UNIVERSITY OF CALIFORNIA AND RESEARCH IN MOTION LIMITED HAS NO
023 OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
024 MODIFICATIONS.
025
026 PT_COPYRIGHT_VERSION_2
027 COPYRIGHTENDKEY
028
029 */
030package ptolemy.math;
031
032import java.math.BigDecimal;
033
034///////////////////////////////////////////////////////////////////
035//// Quantizer
036
037/**
038 This class provides a set of static methods for creating instances of
039 the FixPoint class from doubles, integers, or fixed point numbers.
040 The various round() methods return a fixed point value that is nearest
041 to the specified number, but has the specified precision.  The various
042 roundToZero() and truncate() methods return a fixed point value that
043 is nearest to the specified number, but no greater in magnitude.  The
044 various roundDown() methods return a the nearest fixed point less than
045 the argument. The intention is to fill out this class with roundUp(),
046 and roundNearestEven().  All of these methods may introduce
047 quantization errors and/or overflow.
048
049 This class has been reimplemented to perform all rounding by first
050 constructing a FixPointQuantization and then using either the quantizing
051 constructor of FixPoint or FixPoint.quantize. Users may find that their
052 code simplifies if they do likewise.
053
054 @author Bart Kienhuis, Edward A. Lee, Ed Willink
055 @version $Id$
056 @since Ptolemy II 0.4
057 @Pt.ProposedRating Yellow (kienhuis)
058 @Pt.AcceptedRating Red (kienhuis)
059 @see FixPoint
060 @see Overflow
061 @see Precision
062 @see Rounding
063 @see Quantization
064 */
065public class Quantizer {
066    // The only constructor is private so that this class cannot
067    // be instantiated.
068    private Quantizer() {
069    }
070
071    ///////////////////////////////////////////////////////////////////
072    ////                         public methods                    ////
073
074    /** Return the fixed point number that is nearest to the specified
075     *  value, but has the given precision, possibly introducing
076     *  quantization or overflow errors.
077     *  An overflow error occurs if the specified number does not fit
078     *  within the range possible with the specified precision. In that
079     *  case, the returned value is either the maximum or minimum value
080     *  possible with the given precision, depending on the sign of the
081     *  specified number.
082     *
083     *  @param value The value to represent.
084     *  @param precision The precision of the representation.
085     *  @return A fixed-point representation of the value.
086     */
087    public static FixPoint round(double value, Precision precision) {
088        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
089                Rounding.NEAREST);
090        return new FixPoint(new BigDecimal(value), q);
091    }
092
093    /** Return the fixed point number that is nearest to the specified
094     *  value, but has the given precision, possibly introducing
095     *  quantization or overflow errors.
096     *  An overflow error occurs if the specified number does not fit
097     *  within the range possible with the specified precision. In that
098     *  case, the returned value is either the maximum or minimum value
099     *  possible with the given precision, depending on the sign of the
100     *  specified number.
101     *
102     *  @param value The value to represent.
103     *  @param precision The precision of the representation.
104     *  @return A fixed-point representation of the value.
105     */
106    public static FixPoint round(BigDecimal value, Precision precision) {
107        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
108                Rounding.NEAREST);
109        return new FixPoint(value, q);
110    }
111
112    /** Return the fixed point number that is nearest to the specified
113     *  value, but has the given precision, possibly introducing
114     *  quantization or overflow errors.
115     *  An overflow error occurs if the specified number does not fit
116     *  within the range possible with the specified precision. In that
117     *  case, the returned value depends on the specified mode.
118     *  If the mode is SATURATE, then the return value is either
119     *  the maximum or minimum value possible with the given
120     *  precision, depending on the sign of the
121     *  specified number.  If the mode is OVERFLOW_TO_ZERO,
122     *  then the return value is zero.
123     *
124     *  @param value The value to represent.
125     *  @param newPrecision The precision of the representation.
126     *  @param mode The overflow mode.
127     *  @return A new fixed-point representation of the value.
128     */
129    public static FixPoint round(FixPoint value, Precision newPrecision,
130            Overflow mode) {
131        Quantization q = new FixPointQuantization(newPrecision, mode,
132                Rounding.NEAREST);
133        return value.quantize(q);
134    }
135
136    /** Return the nearest fixed point number with less than or equal
137     *  magnitude that has the given precision, possibly introducing
138     *  quantization or overflow errors.
139     *  An overflow error occurs if the specified number does not fit
140     *  within the range possible with the specified precision. In that
141     *  case, the returned value is either the maximum or minimum value
142     *  possible with the given precision, depending on the sign of the
143     *  specified number.
144     *
145     *  @param value The value to represent.
146     *  @param precision The precision of the representation.
147     *  @return A fixed-point representation of the value.
148     */
149    public static FixPoint roundDown(double value, Precision precision) {
150        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
151                Rounding.DOWN);
152        return new FixPoint(new BigDecimal(value), q);
153    }
154
155    /** Return the nearest fixed point number with less than or equal
156     *  magnitude that has the given precision, possibly introducing
157     *  quantization or overflow errors.
158     *  An overflow error occurs if the specified number does not fit
159     *  within the range possible with the specified precision. In that
160     *  case, the returned value is either the maximum or minimum value
161     *  possible with the given precision, depending on the sign of the
162     *  specified number.
163     *
164     *  @param value The value to represent.
165     *  @param precision The precision of the representation.
166     *  @return A fixed-point representation of the value.
167     */
168    public static FixPoint roundDown(BigDecimal value, Precision precision) {
169        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
170                Rounding.DOWN);
171        return new FixPoint(value, q);
172    }
173
174    /** Return the nearest fixed point number with less than or equal
175     *  magnitude that has the given precision, possibly introducing
176     *  quantization or overflow errors.
177     *  An overflow error occurs if the specified number does not fit
178     *  within the range possible with the specified precision. In that
179     *  case, the returned value depends on the specified mode.
180     *  If the mode is SATURATE, then the return value is either
181     *  the maximum or minimum value possible with the given
182     *  precision, depending on the sign of the
183     *  specified number.  If the mode is OVERFLOW_TO_ZERO,
184     *  then the return value is zero.
185     *
186     *  @param value The value to represent.
187     *  @param newPrecision The precision of the representation.
188     *  @param mode The overflow mode.
189     *  @return A new fixed-point representation of the value.
190     */
191    public static FixPoint roundDown(FixPoint value, Precision newPrecision,
192            Overflow mode) {
193        Quantization q = new FixPointQuantization(newPrecision, mode,
194                Rounding.DOWN);
195        return value.quantize(q);
196    }
197
198    /** Return the fixed point number that is nearest to the specified
199     *  value, but has the given precision, possibly introducing
200     *  quantization or overflow errors.  If the rounded digit is
201     *  five, then the last digit that is not discarded will be
202     *  rounded to make it even.  An overflow error occurs if the
203     *  specified number does not fit within the range possible with
204     *  the specified precision. In that case, the returned value is
205     *  either the maximum or minimum value possible with the given
206     *  precision, depending on the sign of the specified number.
207     *
208     *  @param value The value to represent.
209     *  @param precision The precision of the representation.
210     *  @return A fixed-point representation of the value.
211     */
212    public static FixPoint roundNearestEven(double value, Precision precision) {
213        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
214                Rounding.HALF_EVEN);
215        return new FixPoint(new BigDecimal(value), q);
216    }
217
218    /** Return the fixed point number that is nearest to the specified
219     *  value, but has the given precision, possibly introducing
220     *  quantization or overflow errors.  If the rounded digit is
221     *  five, then the last digit that is not discarded will be
222     *  rounded to make it even.  An overflow error occurs if the
223     *  specified number does not fit within the range possible with
224     *  the specified precision. In that case, the returned value is
225     *  either the maximum or minimum value possible with the given
226     *  precision, depending on the sign of the specified number.
227     *
228     *  @param value The value to represent.
229     *  @param precision The precision of the representation.
230     *  @return A fixed-point representation of the value.
231     */
232    public static FixPoint roundNearestEven(BigDecimal value,
233            Precision precision) {
234        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
235                Rounding.HALF_EVEN);
236        return new FixPoint(value, q);
237    }
238
239    /** Return the fixed point number that is nearest to the specified
240     *  value, but has the given precision, possibly introducing
241     *  quantization or overflow errors.  If the rounded digit is
242     *  five, then the last digit that is not discarded will be
243     *  rounded to make it even.  An overflow error occurs if the
244     *  specified number does not fit within the range possible with
245     *  the specified precision. In that case, the returned value
246     *  depends on the specified mode.  If the mode is SATURATE, then
247     *  the return value is either the maximum or minimum value
248     *  possible with the given precision, depending on the sign of
249     *  the specified number.  If the mode is OVERFLOW_TO_ZERO, then
250     *  the return value is zero.
251     *
252     *  @param value The value to represent.
253     *  @param newPrecision The precision of the representation.
254     *  @param mode The overflow mode.
255     *  @return A new fixed-point representation of the value.
256     */
257    public static FixPoint roundNearestEven(FixPoint value,
258            Precision newPrecision, Overflow mode) {
259        Quantization q = new FixPointQuantization(newPrecision, mode,
260                Rounding.HALF_EVEN);
261        return value.quantize(q);
262    }
263
264    /** Return the fixed point number that is nearest to the specified
265     *  value, but has magnitude no greater that the specified value,
266     *  and has the given precision, possibly introducing
267     *  quantization or overflow errors.
268     *  An overflow error occurs if the specified number does not fit
269     *  within the range possible with the specified precision. In that
270     *  case, the returned value is either the maximum or minimum value
271     *  possible with the given precision, depending on the sign of the
272     *  specified number.
273     *
274     *  @param value The value to represent.
275     *  @param precision The precision of the representation.
276     *  @return A fixed-point representation of the value.
277     */
278    public static FixPoint roundToZero(double value, Precision precision) {
279        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
280                Rounding.DOWN);
281        return new FixPoint(new BigDecimal(value), q);
282    }
283
284    /** Return the fixed point number that is nearest to the specified
285     *  value, but has magnitude no greater that the specified value,
286     *  and has the given precision, possibly introducing
287     *  quantization or overflow errors.
288     *  An overflow error occurs if the specified number does not fit
289     *  within the range possible with the specified precision. In that
290     *  case, the returned value is either the maximum or minimum value
291     *  possible with the given precision, depending on the sign of the
292     *  specified number.
293     *
294     *  @param value The value to represent.
295     *  @param precision The precision of the representation.
296     *  @return A fixed-point representation of the value.
297     */
298    public static FixPoint roundToZero(BigDecimal value, Precision precision) {
299        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
300                Rounding.DOWN);
301        return new FixPoint(value, q);
302    }
303
304    /** Return the fixed point number that is nearest to the specified
305     *  value, but has magnitude no greater than the specified value,
306     *  and has the given precision, possibly introducing
307     *  quantization or overflow errors.
308     *  An overflow error occurs if the specified number does not fit
309     *  within the range possible with the specified precision. In that
310     *  case, the returned value depends on the specified mode.
311     *  If the mode is SATURATE, then the return value is either
312     *  the maximum or minimum value possible with the given
313     *  precision, depending on the sign of the
314     *  specified number.  If the mode is OVERFLOW_TO_ZERO,
315     *  then the return value is zero.
316     *
317     *  @param value The value to represent.
318     *  @param newPrecision The precision of the representation.
319     *  @param mode The overflow mode.
320     *  @return A new fixed-point representation of the value.
321     */
322    public static FixPoint roundToZero(FixPoint value, Precision newPrecision,
323            Overflow mode) {
324        Quantization q = new FixPointQuantization(newPrecision, mode,
325                Rounding.DOWN);
326        return value.quantize(q);
327    }
328
329    /** Return the smallest greater than or equal fixed point number
330     *  that has the given precision, possibly introducing
331     *  quantization or overflow errors.
332     *  An overflow error occurs if the specified number does not fit
333     *  within the range possible with the specified precision. In that
334     *  case, the returned value is either the maximum or minimum value
335     *  possible with the given precision, depending on the sign of the
336     *  specified number.
337     *
338     *  @param value The value to represent.
339     *  @param precision The precision of the representation.
340     *  @return A fixed-point representation of the value.
341     */
342    public static FixPoint roundUp(double value, Precision precision) {
343        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
344                Rounding.UP);
345        return new FixPoint(new BigDecimal(value), q);
346    }
347
348    /** Return the smallest greater than or equal fixed point number
349     *  that has the given precision, possibly introducing
350     *  quantization or overflow errors.
351     *  An overflow error occurs if the specified number does not fit
352     *  within the range possible with the specified precision. In that
353     *  case, the returned value is either the maximum or minimum value
354     *  possible with the given precision, depending on the sign of the
355     *  specified number.
356     *
357     *  @param value The value to represent.
358     *  @param precision The precision of the representation.
359     *  @return A fixed-point representation of the value.
360     */
361    public static FixPoint roundUp(BigDecimal value, Precision precision) {
362        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
363                Rounding.UP);
364        return new FixPoint(value, q);
365    }
366
367    /** Return the smallest greater than or equal fixed point number
368     *  that has the given precision, possibly introducing
369     *  quantization or overflow errors.
370     *  An overflow error occurs if the specified number does not fit
371     *  within the range possible with the specified precision. In that
372     *  case, the returned value depends on the specified mode.
373     *  If the mode is SATURATE, then the return value is either
374     *  the maximum or minimum value possible with the given
375     *  precision, depending on the sign of the
376     *  specified number.  If the mode is OVERFLOW_TO_ZERO,
377     *  then the return value is zero.
378     *
379     *  @param value The value to represent.
380     *  @param newPrecision The precision of the representation.
381     *  @param mode The overflow mode.
382     *  @return A new fixed-point representation of the value.
383     */
384    public static FixPoint roundUp(FixPoint value, Precision newPrecision,
385            Overflow mode) {
386        Quantization q = new FixPointQuantization(newPrecision, mode,
387                Rounding.UP);
388        return value.quantize(q);
389    }
390
391    /** Return the fixed point number that is nearest to the specified
392     *  value, but has magnitude no greater that the specified value,
393     *  and has the given precision, possibly introducing quantization
394     *  or overflow errors.  An overflow error occurs if the specified
395     *  number does not fit within the range possible with the
396     *  specified precision. In that case, the returned value is
397     *  either the maximum or minimum value possible with the given
398     *  precision, depending on the sign of the specified number.
399     *
400     *  <p> Note: This method does NOT perform truncation per most
401     *  fixed-point DSP implementations, which simply drop the
402     *  fractional bits.  Most models of fixed-point algorithms will
403     *  use the roundDown methods in this class instead.
404     *  @param value The value to represent.
405     *  @param precision The precision of the representation.
406     *  @return A fixed-point representation of the value.
407     *  @deprecated Use roundToZero instead.
408     */
409    @Deprecated
410    public static FixPoint truncate(double value, Precision precision) {
411        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
412                Rounding.TRUNCATE);
413        return new FixPoint(new BigDecimal(value), q);
414    }
415
416    /** Return the fixed point number that is nearest to the specified
417     *  value, but has magnitude no greater that the specified value,
418     *  and has the given precision, possibly introducing
419     *  quantization or overflow errors.
420     *  An overflow error occurs if the specified number does not fit
421     *  within the range possible with the specified precision. In that
422     *  case, the returned value is either the maximum or minimum value
423     *  possible with the given precision, depending on the sign of the
424     *  specified number.
425     *
426     *  <p> Note: This method does NOT perform truncation per most
427     *  fixed-point DSP implementations, which simply drop the
428     *  fractional bits.  Most models of fixed-point algorithms will
429     *  use the roundDown methods in this class instead.
430     *  @param value The value to represent.
431     *  @param precision The precision of the representation.
432     *  @return A fixed-point representation of the value.
433     *  @deprecated Use roundToZero instead.
434     */
435    @Deprecated
436    public static FixPoint truncate(BigDecimal value, Precision precision) {
437        Quantization q = new FixPointQuantization(precision, Overflow.SATURATE,
438                Rounding.TRUNCATE);
439        return new FixPoint(value, q);
440    }
441
442    /** Return the fixed point number that is nearest to the specified
443     *  value, but has magnitude no greater than the specified value,
444     *  and has the given precision, possibly introducing
445     *  quantization or overflow errors.
446     *  An overflow error occurs if the specified number does not fit
447     *  within the range possible with the specified precision. In that
448     *  case, the returned value depends on the specified mode.
449     *  If the mode is SATURATE, then the return value is either
450     *  the maximum or minimum value possible with the given
451     *  precision, depending on the sign of the
452     *  specified number.  If the mode is OVERFLOW_TO_ZERO,
453     *  then the return value is zero.
454     *
455     *  <p> Note: This method does NOT perform truncation per most
456     *  fixed-point DSP implementations, which simply drop the
457     *  fractional bits.  Most models of fixed-point algorithms will
458     *  use the roundDown methods in this class instead.
459     *  @param value The value to represent.
460     *  @param newPrecision The precision of the representation.
461     *  @param mode The overflow mode.
462     *  @return A new fixed-point representation of the value.
463     *  @deprecated Use roundToZero instead.
464     */
465    @Deprecated
466    public static FixPoint truncate(FixPoint value, Precision newPrecision,
467            Overflow mode) {
468        Quantization q = new FixPointQuantization(newPrecision, mode,
469                Rounding.TRUNCATE);
470        return value.quantize(q);
471    }
472
473    ///////////////////////////////////////////////////////////////////
474    ////                         public variables                  ////
475
476    /** Indicate that overflow should saturate. */
477    public static final Overflow SATURATE = Overflow.SATURATE;
478
479    /** Indicate that overflow should result in a zero value. */
480    public static final Overflow OVERFLOW_TO_ZERO = Overflow.TO_ZERO;
481}