001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.math4.legacy.core.dfp;
019
020/** Subclass of {@link Dfp} which hides the radix-10000 artifacts of the superclass.
021 * This should give outward appearances of being a decimal number with DIGITS*4-3
022 * decimal digits. This class can be subclassed to appear to be an arbitrary number
023 * of decimal digits less than DIGITS*4-3.
024 * @since 2.2
025 */
026public class DfpDec extends Dfp {
027
028    /** Makes an instance with a value of zero.
029     * @param factory factory linked to this instance
030     */
031    protected DfpDec(final DfpField factory) {
032        super(factory);
033    }
034
035    /** Create an instance from a byte value.
036     * @param factory factory linked to this instance
037     * @param x value to convert to an instance
038     */
039    protected DfpDec(final DfpField factory, byte x) {
040        super(factory, x);
041    }
042
043    /** Create an instance from an int value.
044     * @param factory factory linked to this instance
045     * @param x value to convert to an instance
046     */
047    protected DfpDec(final DfpField factory, int x) {
048        super(factory, x);
049    }
050
051    /** Create an instance from a long value.
052     * @param factory factory linked to this instance
053     * @param x value to convert to an instance
054     */
055    protected DfpDec(final DfpField factory, long x) {
056        super(factory, x);
057    }
058
059    /** Create an instance from a double value.
060     * @param factory factory linked to this instance
061     * @param x value to convert to an instance
062     */
063    protected DfpDec(final DfpField factory, double x) {
064        super(factory, x);
065        round(0);
066    }
067
068    /** Copy constructor.
069     * @param d instance to copy
070     */
071    public DfpDec(final Dfp d) {
072        super(d);
073        round(0);
074    }
075
076    /** Create an instance from a String representation.
077     * @param factory factory linked to this instance
078     * @param s string representation of the instance
079     */
080    protected DfpDec(final DfpField factory, final String s) {
081        super(factory, s);
082        round(0);
083    }
084
085    /** Creates an instance with a non-finite value.
086     * @param factory factory linked to this instance
087     * @param sign sign of the Dfp to create
088     * @param nans code of the value, must be one of {@link #INFINITE},
089     * {@link #SNAN},  {@link #QNAN}
090     */
091    protected DfpDec(final DfpField factory, final byte sign, final byte nans) {
092        super(factory, sign, nans);
093    }
094
095    /** {@inheritDoc} */
096    @Override
097    public Dfp newInstance() {
098        return new DfpDec(getField());
099    }
100
101    /** {@inheritDoc} */
102    @Override
103    public Dfp newInstance(final byte x) {
104        return new DfpDec(getField(), x);
105    }
106
107    /** {@inheritDoc} */
108    @Override
109    public Dfp newInstance(final int x) {
110        return new DfpDec(getField(), x);
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public Dfp newInstance(final long x) {
116        return new DfpDec(getField(), x);
117    }
118
119    /** {@inheritDoc} */
120    @Override
121    public Dfp newInstance(final double x) {
122        return new DfpDec(getField(), x);
123    }
124
125    /** {@inheritDoc} */
126    @Override
127    public Dfp newInstance(final Dfp d) {
128
129        // make sure we don't mix number with different precision
130        if (getField().getRadixDigits() != d.getField().getRadixDigits()) {
131            getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
132            final Dfp result = newInstance(getZero());
133            result.nans = QNAN;
134            return dotrap(DfpField.FLAG_INVALID, "newInstance", d, result);
135        }
136
137        return new DfpDec(d);
138    }
139
140    /** {@inheritDoc} */
141    @Override
142    public Dfp newInstance(final String s) {
143        return new DfpDec(getField(), s);
144    }
145
146    /** {@inheritDoc} */
147    @Override
148    public Dfp newInstance(final byte sign, final byte nans) {
149        return new DfpDec(getField(), sign, nans);
150    }
151
152    /** Get the number of decimal digits this class is going to represent.
153     * Default implementation returns {@link #getRadixDigits()}*4-3. Subclasses can
154     * override this to return something less.
155     * @return number of decimal digits this class is going to represent
156     */
157    protected int getDecimalDigits() {
158        return getRadixDigits() * 4 - 3;
159    }
160
161    /** {@inheritDoc} */
162    @Override
163    protected int round(int in) {
164
165        int msb = mant[mant.length - 1];
166        if (msb == 0) {
167            // special case -- this == zero
168            return 0;
169        }
170
171        int cmaxdigits = mant.length * 4;
172        int lsbthreshold = 1000;
173        while (lsbthreshold > msb) {
174            lsbthreshold /= 10;
175            cmaxdigits--;
176        }
177
178
179        final int digits = getDecimalDigits();
180        final int lsbshift = cmaxdigits - digits;
181        final int lsd = lsbshift / 4;
182
183        lsbthreshold = 1;
184        for (int i = 0; i < lsbshift % 4; i++) {
185            lsbthreshold *= 10;
186        }
187
188        final int lsb = mant[lsd];
189
190        if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) {
191            return super.round(in);
192        }
193
194        int discarded = in;  // not looking at this after this point
195        final int n;
196        if (lsbthreshold == 1) {
197            // look to the next digit for rounding
198            n = (mant[lsd - 1] / 1000) % 10;
199            mant[lsd - 1] %= 1000;
200            discarded |= mant[lsd - 1];
201        } else {
202            n = (lsb * 10 / lsbthreshold) % 10;
203            discarded |= lsb % (lsbthreshold / 10);
204        }
205
206        for (int i = 0; i < lsd; i++) {
207            discarded |= mant[i];    // need to know if there are any discarded bits
208            mant[i] = 0;
209        }
210
211        mant[lsd] = lsb / lsbthreshold * lsbthreshold;
212
213        final boolean inc;
214        switch (getField().getRoundingMode()) {
215        case ROUND_DOWN:
216            inc = false;
217            break;
218
219        case ROUND_UP:
220            inc = (n != 0) || (discarded != 0); // round up if n!=0
221            break;
222
223        case ROUND_HALF_UP:
224            inc = n >= 5;  // round half up
225            break;
226
227        case ROUND_HALF_DOWN:
228            inc = n > 5;  // round half down
229            break;
230
231        case ROUND_HALF_EVEN:
232            inc = (n > 5) ||
233                  (n == 5 && discarded != 0) ||
234                  (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 1);  // round half-even
235            break;
236
237        case ROUND_HALF_ODD:
238            inc = (n > 5) ||
239                  (n == 5 && discarded != 0) ||
240                  (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 0);  // round half-odd
241            break;
242
243        case ROUND_CEIL:
244            inc = (sign == 1) && (n != 0 || discarded != 0);  // round ceil
245            break;
246
247        case ROUND_FLOOR:
248        default:
249            inc = (sign == -1) && (n != 0 || discarded != 0);  // round floor
250            break;
251        }
252
253        if (inc) {
254            // increment if necessary
255            int rh = lsbthreshold;
256            for (int i = lsd; i < mant.length; i++) {
257                final int r = mant[i] + rh;
258                rh = r / RADIX;
259                mant[i] = r % RADIX;
260            }
261
262            if (rh != 0) {
263                shiftRight();
264                mant[mant.length - 1] = rh;
265            }
266        }
267
268        // Check for exceptional cases and raise signals if necessary
269        if (exp < MIN_EXP) {
270            // Gradual Underflow
271            getField().setIEEEFlagsBits(DfpField.FLAG_UNDERFLOW);
272            return DfpField.FLAG_UNDERFLOW;
273        }
274
275        if (exp > MAX_EXP) {
276            // Overflow
277            getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW);
278            return DfpField.FLAG_OVERFLOW;
279        }
280
281        if (n != 0 || discarded != 0) {
282            // Inexact
283            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
284            return DfpField.FLAG_INEXACT;
285        }
286        return 0;
287    }
288
289    /** {@inheritDoc} */
290    @Override
291    public Dfp nextAfter(Dfp x) {
292
293        final String trapName = "nextAfter";
294
295        // make sure we don't mix number with different precision
296        if (getField().getRadixDigits() != x.getField().getRadixDigits()) {
297            getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
298            final Dfp result = newInstance(getZero());
299            result.nans = QNAN;
300            return dotrap(DfpField.FLAG_INVALID, trapName, x, result);
301        }
302
303        boolean up = false;
304        Dfp result;
305        Dfp inc;
306
307        // if this is greater than x
308        if (this.lessThan(x)) {
309            up = true;
310        }
311
312        if (equals(x)) {
313            return newInstance(x);
314        }
315
316        if (lessThan(getZero())) {
317            up = !up;
318        }
319
320        if (up) {
321            inc = power10(intLog10() - getDecimalDigits() + 1);
322            inc = copySign(inc, this);
323
324            if (this.equals(getZero())) {
325                inc = power10K(MIN_EXP - mant.length - 1);
326            }
327
328            if (inc.equals(getZero())) {
329                result = copySign(newInstance(getZero()), this);
330            } else {
331                result = add(inc);
332            }
333        } else {
334            inc = power10(intLog10());
335            inc = copySign(inc, this);
336
337            if (this.equals(inc)) {
338                inc = inc.divide(power10(getDecimalDigits()));
339            } else {
340                inc = inc.divide(power10(getDecimalDigits() - 1));
341            }
342
343            if (this.equals(getZero())) {
344                inc = power10K(MIN_EXP - mant.length - 1);
345            }
346
347            if (inc.equals(getZero())) {
348                result = copySign(newInstance(getZero()), this);
349            } else {
350                result = subtract(inc);
351            }
352        }
353
354        if (result.classify() == INFINITE && this.classify() != INFINITE) {
355            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
356            result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
357        }
358
359        if (result.equals(getZero()) && !this.equals(getZero())) {
360            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
361            result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
362        }
363
364        return result;
365    }
366}