View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.dfp;
24  
25  /** Subclass of {@link Dfp} which hides the radix-10000 artifacts of the superclass.
26   * This should give outward appearances of being a decimal number with DIGITS*4-3
27   * decimal digits. This class can be subclassed to appear to be an arbitrary number
28   * of decimal digits less than DIGITS*4-3.
29   */
30  public class DfpDec extends Dfp {
31  
32      /** Makes an instance with a value of zero.
33       * @param factory factory linked to this instance
34       */
35      protected DfpDec(final DfpField factory) {
36          super(factory);
37      }
38  
39      /** Create an instance from a byte value.
40       * @param factory factory linked to this instance
41       * @param x value to convert to an instance
42       */
43      protected DfpDec(final DfpField factory, byte x) {
44          super(factory, x);
45      }
46  
47      /** Create an instance from an int value.
48       * @param factory factory linked to this instance
49       * @param x value to convert to an instance
50       */
51      protected DfpDec(final DfpField factory, int x) {
52          super(factory, x);
53      }
54  
55      /** Create an instance from a long value.
56       * @param factory factory linked to this instance
57       * @param x value to convert to an instance
58       */
59      protected DfpDec(final DfpField factory, long x) {
60          super(factory, x);
61      }
62  
63      /** Create an instance from a double value.
64       * @param factory factory linked to this instance
65       * @param x value to convert to an instance
66       */
67      protected DfpDec(final DfpField factory, double x) {
68          super(factory, x);
69          round(0);
70      }
71  
72      /** Copy constructor.
73       * @param d instance to copy
74       */
75      public DfpDec(final Dfp d) {
76          super(d);
77          round(0);
78      }
79  
80      /** Create an instance from a String representation.
81       * @param factory factory linked to this instance
82       * @param s string representation of the instance
83       */
84      protected DfpDec(final DfpField factory, final String s) {
85          super(factory, s);
86          round(0);
87      }
88  
89      /** Creates an instance with a non-finite value.
90       * @param factory factory linked to this instance
91       * @param sign sign of the Dfp to create
92       * @param nans code of the value, must be one of {@link #INFINITE},
93       * {@link #SNAN},  {@link #QNAN}
94       */
95      protected DfpDec(final DfpField factory, final byte sign, final byte nans) {
96          super(factory, sign, nans);
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     public Dfp newInstance() {
102         return new DfpDec(getField());
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public Dfp newInstance(final byte x) {
108         return new DfpDec(getField(), x);
109     }
110 
111     /** {@inheritDoc} */
112     @Override
113     public Dfp newInstance(final int x) {
114         return new DfpDec(getField(), x);
115     }
116 
117     /** {@inheritDoc} */
118     @Override
119     public Dfp newInstance(final long x) {
120         return new DfpDec(getField(), x);
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public Dfp newInstance(final double x) {
126         return new DfpDec(getField(), x);
127     }
128 
129     /** {@inheritDoc} */
130     @Override
131     public Dfp newInstance(final Dfp d) {
132 
133         // make sure we don't mix number with different precision
134         if (getField().getRadixDigits() != d.getField().getRadixDigits()) {
135             getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
136             final Dfp result = newInstance(getZero());
137             result.nans = QNAN;
138             return dotrap(DfpField.FLAG_INVALID, "newInstance", d, result);
139         }
140 
141         return new DfpDec(d);
142 
143     }
144 
145     /** {@inheritDoc} */
146     @Override
147     public Dfp newInstance(final String s) {
148         return new DfpDec(getField(), s);
149     }
150 
151     /** {@inheritDoc} */
152     @Override
153     public Dfp newInstance(final byte sign, final byte nans) {
154         return new DfpDec(getField(), sign, nans);
155     }
156 
157     /** Get the number of decimal digits this class is going to represent.
158      * Default implementation returns {@link #getRadixDigits()}*4-3. Subclasses can
159      * override this to return something less.
160      * @return number of decimal digits this class is going to represent
161      */
162     protected int getDecimalDigits() {
163         return getRadixDigits() * 4 - 3;
164     }
165 
166     /** {@inheritDoc} */
167     @Override
168     protected int round(int in) {
169 
170         int msb = mant[mant.length-1];
171         if (msb == 0) {
172             // special case -- this == zero
173             return 0;
174         }
175 
176         int cmaxdigits = mant.length * 4;
177         int lsbthreshold = 1000;
178         while (lsbthreshold > msb) {
179             lsbthreshold /= 10;
180             cmaxdigits --;
181         }
182 
183 
184         final int digits = getDecimalDigits();
185         final int lsbshift = cmaxdigits - digits;
186         final int lsd = lsbshift / 4;
187 
188         lsbthreshold = 1;
189         for (int i = 0; i < lsbshift % 4; i++) {
190             lsbthreshold *= 10;
191         }
192 
193         final int lsb = mant[lsd];
194 
195         if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) {
196             return super.round(in);
197         }
198 
199         int discarded = in;  // not looking at this after this point
200         final int n;
201         if (lsbthreshold == 1) {
202             // look to the next digit for rounding
203             n = (mant[lsd-1] / 1000) % 10;
204             mant[lsd-1] %= 1000;
205             discarded |= mant[lsd-1];
206         } else {
207             n = (lsb * 10 / lsbthreshold) % 10;
208             discarded |= lsb % (lsbthreshold/10);
209         }
210 
211         for (int i = 0; i < lsd; i++) {
212             discarded |= mant[i];    // need to know if there are any discarded bits
213             mant[i] = 0;
214         }
215 
216         mant[lsd] = lsb / lsbthreshold * lsbthreshold;
217 
218         final boolean inc;
219         switch (getField().getRoundingMode()) {
220             case ROUND_DOWN:
221                 inc = false;
222                 break;
223 
224             case ROUND_UP:
225                 inc = (n != 0) || (discarded != 0); // round up if n!=0
226                 break;
227 
228             case ROUND_HALF_UP:
229                 inc = n >= 5;  // round half up
230                 break;
231 
232             case ROUND_HALF_DOWN:
233                 inc = n > 5;  // round half down
234                 break;
235 
236             case ROUND_HALF_EVEN:
237                 inc = (n > 5) ||
238                       (n == 5 && discarded != 0) ||
239                       (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 1);  // round half-even
240                 break;
241 
242             case ROUND_HALF_ODD:
243                 inc = (n > 5) ||
244                       (n == 5 && discarded != 0) ||
245                       (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 0);  // round half-odd
246                 break;
247 
248             case ROUND_CEIL:
249                 inc = (sign == 1) && (n != 0 || discarded != 0);  // round ceil
250                 break;
251 
252             case ROUND_FLOOR:
253             default:
254                 inc = (sign == -1) && (n != 0 || discarded != 0);  // round floor
255                 break;
256         }
257 
258         if (inc) {
259             // increment if necessary
260             int rh = lsbthreshold;
261             for (int i = lsd; i < mant.length; i++) {
262                 final int r = mant[i] + rh;
263                 rh = r / RADIX;
264                 mant[i] = r % RADIX;
265             }
266 
267             if (rh != 0) {
268                 shiftRight();
269                 mant[mant.length-1]=rh;
270             }
271         }
272 
273         // Check for exceptional cases and raise signals if necessary
274         if (exp < MIN_EXP) {
275             // Gradual Underflow
276             getField().setIEEEFlagsBits(DfpField.FLAG_UNDERFLOW);
277             return DfpField.FLAG_UNDERFLOW;
278         }
279 
280         if (exp > MAX_EXP) {
281             // Overflow
282             getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW);
283             return DfpField.FLAG_OVERFLOW;
284         }
285 
286         if (n != 0 || discarded != 0) {
287             // Inexact
288             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
289             return DfpField.FLAG_INEXACT;
290         }
291         return 0;
292     }
293 
294     /** {@inheritDoc} */
295     @Override
296     public Dfp nextAfter(Dfp x) {
297 
298         final String trapName = "nextAfter";
299 
300         // make sure we don't mix number with different precision
301         if (getField().getRadixDigits() != x.getField().getRadixDigits()) {
302             getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
303             final Dfp result = newInstance(getZero());
304             result.nans = QNAN;
305             return dotrap(DfpField.FLAG_INVALID, trapName, x, result);
306         }
307 
308         boolean up = false;
309         Dfp result;
310         Dfp inc;
311 
312         // if this is greater than x
313         if (this.lessThan(x)) {
314             up = true;
315         }
316 
317         if (equals(x)) {
318             return newInstance(x);
319         }
320 
321         if (lessThan(getZero())) {
322             up = !up;
323         }
324 
325         if (up) {
326             inc = power10(intLog10() - getDecimalDigits() + 1);
327             inc = copysign(inc, this);
328 
329             if (this.equals(getZero())) {
330                 inc = power10K(MIN_EXP-mant.length-1);
331             }
332 
333             if (inc.equals(getZero())) {
334                 result = copysign(newInstance(getZero()), this);
335             } else {
336                 result = add(inc);
337             }
338         } else {
339             inc = power10(intLog10());
340             inc = copysign(inc, this);
341 
342             if (this.equals(inc)) {
343                 inc = inc.divide(power10(getDecimalDigits()));
344             } else {
345                 inc = inc.divide(power10(getDecimalDigits() - 1));
346             }
347 
348             if (this.equals(getZero())) {
349                 inc = power10K(MIN_EXP-mant.length-1);
350             }
351 
352             if (inc.equals(getZero())) {
353                 result = copysign(newInstance(getZero()), this);
354             } else {
355                 result = subtract(inc);
356             }
357         }
358 
359         if (result.classify() == INFINITE && this.classify() != INFINITE) {
360             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
361             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
362         }
363 
364         if (result.equals(getZero()) && !this.equals(getZero())) {
365             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
366             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
367         }
368 
369         return result;
370     }
371 
372 }