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.  *      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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.dfp;

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

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

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

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

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

  55.     /** Create an instance from a double 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, double x) {
  60.         super(factory, x);
  61.         round(0);
  62.     }

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

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

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

  87.     /** {@inheritDoc} */
  88.     @Override
  89.     public Dfp newInstance() {
  90.         return new DfpDec(getField());
  91.     }

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

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

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

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

  112.     /** {@inheritDoc} */
  113.     @Override
  114.     public Dfp newInstance(final Dfp d) {

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

  122.         return new DfpDec(d);

  123.     }

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

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

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

  142.     /** {@inheritDoc} */
  143.     @Override
  144.     protected int round(int in) {

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

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


  156.         final int digits = getDecimalDigits();
  157.         final int lsbshift = cmaxdigits - digits;
  158.         final int lsd = lsbshift / 4;

  159.         lsbthreshold = 1;
  160.         for (int i = 0; i < lsbshift % 4; i++) {
  161.             lsbthreshold *= 10;
  162.         }

  163.         final int lsb = mant[lsd];

  164.         if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) {
  165.             return super.round(in);
  166.         }

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

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

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

  183.         final boolean inc;
  184.         switch (getField().getRoundingMode()) {
  185.             case ROUND_DOWN:
  186.                 inc = false;
  187.                 break;

  188.             case ROUND_UP:
  189.                 inc = (n != 0) || (discarded != 0); // round up if n!=0
  190.                 break;

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

  194.             case ROUND_HALF_DOWN:
  195.                 inc = n > 5;  // round half down
  196.                 break;

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

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

  207.             case ROUND_CEIL:
  208.                 inc = (sign == 1) && (n != 0 || discarded != 0);  // round ceil
  209.                 break;

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

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

  223.             if (rh != 0) {
  224.                 shiftRight();
  225.                 mant[mant.length-1]=rh;
  226.             }
  227.         }

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

  234.         if (exp > MAX_EXP) {
  235.             // Overflow
  236.             getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW);
  237.             return DfpField.FLAG_OVERFLOW;
  238.         }

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

  246.     /** {@inheritDoc} */
  247.     @Override
  248.     public Dfp nextAfter(Dfp x) {

  249.         final String trapName = "nextAfter";

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

  257.         boolean up = false;
  258.         Dfp result;
  259.         Dfp inc;

  260.         // if this is greater than x
  261.         if (this.lessThan(x)) {
  262.             up = true;
  263.         }

  264.         if (equals(x)) {
  265.             return newInstance(x);
  266.         }

  267.         if (lessThan(getZero())) {
  268.             up = !up;
  269.         }

  270.         if (up) {
  271.             inc = power10(intLog10() - getDecimalDigits() + 1);
  272.             inc = copysign(inc, this);

  273.             if (this.equals(getZero())) {
  274.                 inc = power10K(MIN_EXP-mant.length-1);
  275.             }

  276.             if (inc.equals(getZero())) {
  277.                 result = copysign(newInstance(getZero()), this);
  278.             } else {
  279.                 result = add(inc);
  280.             }
  281.         } else {
  282.             inc = power10(intLog10());
  283.             inc = copysign(inc, this);

  284.             if (this.equals(inc)) {
  285.                 inc = inc.divide(power10(getDecimalDigits()));
  286.             } else {
  287.                 inc = inc.divide(power10(getDecimalDigits() - 1));
  288.             }

  289.             if (this.equals(getZero())) {
  290.                 inc = power10K(MIN_EXP-mant.length-1);
  291.             }

  292.             if (inc.equals(getZero())) {
  293.                 result = copysign(newInstance(getZero()), this);
  294.             } else {
  295.                 result = subtract(inc);
  296.             }
  297.         }

  298.         if (result.classify() == INFINITE && this.classify() != INFINITE) {
  299.             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
  300.             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
  301.         }

  302.         if (result.equals(getZero()) && !this.equals(getZero())) {
  303.             getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT);
  304.             result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result);
  305.         }

  306.         return result;
  307.     }

  308. }