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