DfpDec.java

  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.  *      http://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. package org.apache.commons.math4.legacy.core.dfp;

  18. /** Subclass of {@link Dfp} which hides the radix-10000 artifacts of the superclass.
  19.  * This should give outward appearances of being a decimal number with DIGITS*4-3
  20.  * decimal digits. This class can be subclassed to appear to be an arbitrary number
  21.  * of decimal digits less than DIGITS*4-3.
  22.  * @since 2.2
  23.  */
  24. public class DfpDec extends Dfp {

  25.     /** Makes an instance with a value of zero.
  26.      * @param factory factory linked to this instance
  27.      */
  28.     protected DfpDec(final DfpField factory) {
  29.         super(factory);
  30.     }

  31.     /** Create an instance from a byte value.
  32.      * @param factory factory linked to this instance
  33.      * @param x value to convert to an instance
  34.      */
  35.     protected DfpDec(final DfpField factory, byte x) {
  36.         super(factory, x);
  37.     }

  38.     /** Create an instance from an int value.
  39.      * @param factory factory linked to this instance
  40.      * @param x value to convert to an instance
  41.      */
  42.     protected DfpDec(final DfpField factory, int x) {
  43.         super(factory, x);
  44.     }

  45.     /** Create an instance from a long value.
  46.      * @param factory factory linked to this instance
  47.      * @param x value to convert to an instance
  48.      */
  49.     protected DfpDec(final DfpField factory, long x) {
  50.         super(factory, x);
  51.     }

  52.     /** Create an instance from a double value.
  53.      * @param factory factory linked to this instance
  54.      * @param x value to convert to an instance
  55.      */
  56.     protected DfpDec(final DfpField factory, double x) {
  57.         super(factory, x);
  58.         round(0);
  59.     }

  60.     /** Copy constructor.
  61.      * @param d instance to copy
  62.      */
  63.     public DfpDec(final Dfp d) {
  64.         super(d);
  65.         round(0);
  66.     }

  67.     /** Create an instance from a String representation.
  68.      * @param factory factory linked to this instance
  69.      * @param s string representation of the instance
  70.      */
  71.     protected DfpDec(final DfpField factory, final String s) {
  72.         super(factory, s);
  73.         round(0);
  74.     }

  75.     /** Creates an instance with a non-finite value.
  76.      * @param factory factory linked to this instance
  77.      * @param sign sign of the Dfp to create
  78.      * @param nans code of the value, must be one of {@link #INFINITE},
  79.      * {@link #SNAN},  {@link #QNAN}
  80.      */
  81.     protected DfpDec(final DfpField factory, final byte sign, final byte nans) {
  82.         super(factory, sign, nans);
  83.     }

  84.     /** {@inheritDoc} */
  85.     @Override
  86.     public Dfp newInstance() {
  87.         return new DfpDec(getField());
  88.     }

  89.     /** {@inheritDoc} */
  90.     @Override
  91.     public Dfp newInstance(final byte x) {
  92.         return new DfpDec(getField(), x);
  93.     }

  94.     /** {@inheritDoc} */
  95.     @Override
  96.     public Dfp newInstance(final int x) {
  97.         return new DfpDec(getField(), x);
  98.     }

  99.     /** {@inheritDoc} */
  100.     @Override
  101.     public Dfp newInstance(final long x) {
  102.         return new DfpDec(getField(), x);
  103.     }

  104.     /** {@inheritDoc} */
  105.     @Override
  106.     public Dfp newInstance(final double x) {
  107.         return new DfpDec(getField(), x);
  108.     }

  109.     /** {@inheritDoc} */
  110.     @Override
  111.     public Dfp newInstance(final Dfp d) {

  112.         // make sure we don't mix number with different precision
  113.         if (getField().getRadixDigits() != d.getField().getRadixDigits()) {
  114.             getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  115.             final Dfp result = newInstance(getZero());
  116.             result.nans = QNAN;
  117.             return dotrap(DfpField.FLAG_INVALID, "newInstance", d, result);
  118.         }

  119.         return new DfpDec(d);
  120.     }

  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public Dfp newInstance(final String s) {
  124.         return new DfpDec(getField(), s);
  125.     }

  126.     /** {@inheritDoc} */
  127.     @Override
  128.     public Dfp newInstance(final byte sign, final byte nans) {
  129.         return new DfpDec(getField(), sign, nans);
  130.     }

  131.     /** Get the number of decimal digits this class is going to represent.
  132.      * Default implementation returns {@link #getRadixDigits()}*4-3. Subclasses can
  133.      * override this to return something less.
  134.      * @return number of decimal digits this class is going to represent
  135.      */
  136.     protected int getDecimalDigits() {
  137.         return getRadixDigits() * 4 - 3;
  138.     }

  139.     /** {@inheritDoc} */
  140.     @Override
  141.     protected int round(int in) {

  142.         int msb = mant[mant.length - 1];
  143.         if (msb == 0) {
  144.             // special case -- this == zero
  145.             return 0;
  146.         }

  147.         int cmaxdigits = mant.length * 4;
  148.         int lsbthreshold = 1000;
  149.         while (lsbthreshold > msb) {
  150.             lsbthreshold /= 10;
  151.             cmaxdigits--;
  152.         }


  153.         final int digits = getDecimalDigits();
  154.         final int lsbshift = cmaxdigits - digits;
  155.         final int lsd = lsbshift / 4;

  156.         lsbthreshold = 1;
  157.         for (int i = 0; i < lsbshift % 4; i++) {
  158.             lsbthreshold *= 10;
  159.         }

  160.         final int lsb = mant[lsd];

  161.         if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) {
  162.             return super.round(in);
  163.         }

  164.         int discarded = in;  // not looking at this after this point
  165.         final int n;
  166.         if (lsbthreshold == 1) {
  167.             // look to the next digit for rounding
  168.             n = (mant[lsd - 1] / 1000) % 10;
  169.             mant[lsd - 1] %= 1000;
  170.             discarded |= mant[lsd - 1];
  171.         } else {
  172.             n = (lsb * 10 / lsbthreshold) % 10;
  173.             discarded |= lsb % (lsbthreshold / 10);
  174.         }

  175.         for (int i = 0; i < lsd; i++) {
  176.             discarded |= mant[i];    // need to know if there are any discarded bits
  177.             mant[i] = 0;
  178.         }

  179.         mant[lsd] = lsb / lsbthreshold * lsbthreshold;

  180.         final boolean inc;
  181.         switch (getField().getRoundingMode()) {
  182.         case ROUND_DOWN:
  183.             inc = false;
  184.             break;

  185.         case ROUND_UP:
  186.             inc = (n != 0) || (discarded != 0); // round up if n!=0
  187.             break;

  188.         case ROUND_HALF_UP:
  189.             inc = n >= 5;  // round half up
  190.             break;

  191.         case ROUND_HALF_DOWN:
  192.             inc = n > 5;  // round half down
  193.             break;

  194.         case ROUND_HALF_EVEN:
  195.             inc = (n > 5) ||
  196.                   (n == 5 && discarded != 0) ||
  197.                   (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 1);  // round half-even
  198.             break;

  199.         case ROUND_HALF_ODD:
  200.             inc = (n > 5) ||
  201.                   (n == 5 && discarded != 0) ||
  202.                   (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 0);  // round half-odd
  203.             break;

  204.         case ROUND_CEIL:
  205.             inc = (sign == 1) && (n != 0 || discarded != 0);  // round ceil
  206.             break;

  207.         case ROUND_FLOOR:
  208.         default:
  209.             inc = (sign == -1) && (n != 0 || discarded != 0);  // round floor
  210.             break;
  211.         }

  212.         if (inc) {
  213.             // increment if necessary
  214.             int rh = lsbthreshold;
  215.             for (int i = lsd; i < mant.length; i++) {
  216.                 final int r = mant[i] + rh;
  217.                 rh = r / RADIX;
  218.                 mant[i] = r % RADIX;
  219.             }

  220.             if (rh != 0) {
  221.                 shiftRight();
  222.                 mant[mant.length - 1] = rh;
  223.             }
  224.         }

  225.         // Check for exceptional cases and raise signals if necessary
  226.         if (exp < MIN_EXP) {
  227.             // Gradual Underflow
  228.             getField().setIEEEFlagsBits(DfpField.FLAG_UNDERFLOW);
  229.             return DfpField.FLAG_UNDERFLOW;
  230.         }

  231.         if (exp > MAX_EXP) {
  232.             // Overflow
  233.             getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW);
  234.             return DfpField.FLAG_OVERFLOW;
  235.         }

  236.         if (n != 0 || discarded != 0) {
  237.             // Inexact
  238.             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
  239.             return DfpField.FLAG_INEXACT;
  240.         }
  241.         return 0;
  242.     }

  243.     /** {@inheritDoc} */
  244.     @Override
  245.     public Dfp nextAfter(Dfp x) {

  246.         final String trapName = "nextAfter";

  247.         // make sure we don't mix number with different precision
  248.         if (getField().getRadixDigits() != x.getField().getRadixDigits()) {
  249.             getField().setIEEEFlagsBits(DfpField.FLAG_INVALID);
  250.             final Dfp result = newInstance(getZero());
  251.             result.nans = QNAN;
  252.             return dotrap(DfpField.FLAG_INVALID, trapName, x, result);
  253.         }

  254.         boolean up = false;
  255.         Dfp result;
  256.         Dfp inc;

  257.         // if this is greater than x
  258.         if (this.lessThan(x)) {
  259.             up = true;
  260.         }

  261.         if (equals(x)) {
  262.             return newInstance(x);
  263.         }

  264.         if (lessThan(getZero())) {
  265.             up = !up;
  266.         }

  267.         if (up) {
  268.             inc = power10(intLog10() - getDecimalDigits() + 1);
  269.             inc = copySign(inc, this);

  270.             if (this.equals(getZero())) {
  271.                 inc = power10K(MIN_EXP - mant.length - 1);
  272.             }

  273.             if (inc.equals(getZero())) {
  274.                 result = copySign(newInstance(getZero()), this);
  275.             } else {
  276.                 result = add(inc);
  277.             }
  278.         } else {
  279.             inc = power10(intLog10());
  280.             inc = copySign(inc, this);

  281.             if (this.equals(inc)) {
  282.                 inc = inc.divide(power10(getDecimalDigits()));
  283.             } else {
  284.                 inc = inc.divide(power10(getDecimalDigits() - 1));
  285.             }

  286.             if (this.equals(getZero())) {
  287.                 inc = power10K(MIN_EXP - mant.length - 1);
  288.             }

  289.             if (inc.equals(getZero())) {
  290.                 result = copySign(newInstance(getZero()), this);
  291.             } else {
  292.                 result = subtract(inc);
  293.             }
  294.         }

  295.         if (result.classify() == INFINITE && this.classify() != INFINITE) {
  296.             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
  297.             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
  298.         }

  299.         if (result.equals(getZero()) && !this.equals(getZero())) {
  300.             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
  301.             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
  302.         }

  303.         return result;
  304.     }
  305. }