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.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
141    /** {@inheritDoc} */
142    @Override
143    public Dfp newInstance(final String s) {
144        return new DfpDec(getField(), s);
145    }
146
147    /** {@inheritDoc} */
148    @Override
149    public Dfp newInstance(final byte sign, final byte nans) {
150        return new DfpDec(getField(), sign, nans);
151    }
152
153    /** Get the number of decimal digits this class is going to represent.
154     * Default implementation returns {@link #getRadixDigits()}*4-3. Subclasses can
155     * override this to return something less.
156     * @return number of decimal digits this class is going to represent
157     */
158    protected int getDecimalDigits() {
159        return getRadixDigits() * 4 - 3;
160    }
161
162    /** {@inheritDoc} */
163    @Override
164    protected int round(int in) {
165
166        int msb = mant[mant.length-1];
167        if (msb == 0) {
168            // special case -- this == zero
169            return 0;
170        }
171
172        int cmaxdigits = mant.length * 4;
173        int lsbthreshold = 1000;
174        while (lsbthreshold > msb) {
175            lsbthreshold /= 10;
176            cmaxdigits --;
177        }
178
179
180        final int digits = getDecimalDigits();
181        final int lsbshift = cmaxdigits - digits;
182        final int lsd = lsbshift / 4;
183
184        lsbthreshold = 1;
185        for (int i = 0; i < lsbshift % 4; i++) {
186            lsbthreshold *= 10;
187        }
188
189        final int lsb = mant[lsd];
190
191        if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) {
192            return super.round(in);
193        }
194
195        int discarded = in;  // not looking at this after this point
196        final int n;
197        if (lsbthreshold == 1) {
198            // look to the next digit for rounding
199            n = (mant[lsd-1] / 1000) % 10;
200            mant[lsd-1] %= 1000;
201            discarded |= mant[lsd-1];
202        } else {
203            n = (lsb * 10 / lsbthreshold) % 10;
204            discarded |= lsb % (lsbthreshold/10);
205        }
206
207        for (int i = 0; i < lsd; i++) {
208            discarded |= mant[i];    // need to know if there are any discarded bits
209            mant[i] = 0;
210        }
211
212        mant[lsd] = lsb / lsbthreshold * lsbthreshold;
213
214        final boolean inc;
215        switch (getField().getRoundingMode()) {
216            case ROUND_DOWN:
217                inc = false;
218                break;
219
220            case ROUND_UP:
221                inc = (n != 0) || (discarded != 0); // round up if n!=0
222                break;
223
224            case ROUND_HALF_UP:
225                inc = n >= 5;  // round half up
226                break;
227
228            case ROUND_HALF_DOWN:
229                inc = n > 5;  // round half down
230                break;
231
232            case ROUND_HALF_EVEN:
233                inc = (n > 5) ||
234                      (n == 5 && discarded != 0) ||
235                      (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 1);  // round half-even
236                break;
237
238            case ROUND_HALF_ODD:
239                inc = (n > 5) ||
240                      (n == 5 && discarded != 0) ||
241                      (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 0);  // round half-odd
242                break;
243
244            case ROUND_CEIL:
245                inc = (sign == 1) && (n != 0 || discarded != 0);  // round ceil
246                break;
247
248            case ROUND_FLOOR:
249            default:
250                inc = (sign == -1) && (n != 0 || discarded != 0);  // round floor
251                break;
252        }
253
254        if (inc) {
255            // increment if necessary
256            int rh = lsbthreshold;
257            for (int i = lsd; i < mant.length; i++) {
258                final int r = mant[i] + rh;
259                rh = r / RADIX;
260                mant[i] = r % RADIX;
261            }
262
263            if (rh != 0) {
264                shiftRight();
265                mant[mant.length-1]=rh;
266            }
267        }
268
269        // Check for exceptional cases and raise signals if necessary
270        if (exp < MIN_EXP) {
271            // Gradual Underflow
272            getField().setIEEEFlagsBits(DfpField.FLAG_UNDERFLOW);
273            return DfpField.FLAG_UNDERFLOW;
274        }
275
276        if (exp > MAX_EXP) {
277            // Overflow
278            getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW);
279            return DfpField.FLAG_OVERFLOW;
280        }
281
282        if (n != 0 || discarded != 0) {
283            // Inexact
284            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
285            return DfpField.FLAG_INEXACT;
286        }
287        return 0;
288    }
289
290    /** {@inheritDoc} */
291    @Override
292    public Dfp nextAfter(Dfp x) {
293
294        final String trapName = "nextAfter";
295
296        // make sure we don't mix number with different precision
297        if (getField().getRadixDigits() != x.getField().getRadixDigits()) {
298            getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
299            final Dfp result = newInstance(getZero());
300            result.nans = QNAN;
301            return dotrap(DfpField.FLAG_INVALID, trapName, x, result);
302        }
303
304        boolean up = false;
305        Dfp result;
306        Dfp inc;
307
308        // if this is greater than x
309        if (this.lessThan(x)) {
310            up = true;
311        }
312
313        if (equals(x)) {
314            return newInstance(x);
315        }
316
317        if (lessThan(getZero())) {
318            up = !up;
319        }
320
321        if (up) {
322            inc = power10(intLog10() - getDecimalDigits() + 1);
323            inc = copysign(inc, this);
324
325            if (this.equals(getZero())) {
326                inc = power10K(MIN_EXP-mant.length-1);
327            }
328
329            if (inc.equals(getZero())) {
330                result = copysign(newInstance(getZero()), this);
331            } else {
332                result = add(inc);
333            }
334        } else {
335            inc = power10(intLog10());
336            inc = copysign(inc, this);
337
338            if (this.equals(inc)) {
339                inc = inc.divide(power10(getDecimalDigits()));
340            } else {
341                inc = inc.divide(power10(getDecimalDigits() - 1));
342            }
343
344            if (this.equals(getZero())) {
345                inc = power10K(MIN_EXP-mant.length-1);
346            }
347
348            if (inc.equals(getZero())) {
349                result = copysign(newInstance(getZero()), this);
350            } else {
351                result = subtract(inc);
352            }
353        }
354
355        if (result.classify() == INFINITE && this.classify() != INFINITE) {
356            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
357            result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
358        }
359
360        if (result.equals(getZero()) && this.equals(getZero()) == false) {
361            getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
362            result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
363        }
364
365        return result;
366    }
367
368}