| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.math.dfp; |
| |
| /** Subclass of {@link Dfp} which hides the radix-10000 artifacts of the superclass. |
| * This should give outward appearances of being a decimal number with DIGITS*4-3 |
| * decimal digits. This class can be subclassed to appear to be an arbitrary number |
| * of decimal digits less than DIGITS*4-3. |
| * @version $Revision: 1003892 $ $Date: 2010-10-02 23:28:56 +0200 (sam. 02 oct. 2010) $ |
| * @since 2.2 |
| */ |
| public class DfpDec extends Dfp { |
| |
| /** Makes an instance with a value of zero. |
| * @param factory factory linked to this instance |
| */ |
| protected DfpDec(final DfpField factory) { |
| super(factory); |
| } |
| |
| /** Create an instance from a byte value. |
| * @param factory factory linked to this instance |
| * @param x value to convert to an instance |
| */ |
| protected DfpDec(final DfpField factory, byte x) { |
| super(factory, x); |
| } |
| |
| /** Create an instance from an int value. |
| * @param factory factory linked to this instance |
| * @param x value to convert to an instance |
| */ |
| protected DfpDec(final DfpField factory, int x) { |
| super(factory, x); |
| } |
| |
| /** Create an instance from a long value. |
| * @param factory factory linked to this instance |
| * @param x value to convert to an instance |
| */ |
| protected DfpDec(final DfpField factory, long x) { |
| super(factory, x); |
| } |
| |
| /** Create an instance from a double value. |
| * @param factory factory linked to this instance |
| * @param x value to convert to an instance |
| */ |
| protected DfpDec(final DfpField factory, double x) { |
| super(factory, x); |
| round(0); |
| } |
| |
| /** Copy constructor. |
| * @param d instance to copy |
| */ |
| public DfpDec(final Dfp d) { |
| super(d); |
| round(0); |
| } |
| |
| /** Create an instance from a String representation. |
| * @param factory factory linked to this instance |
| * @param s string representation of the instance |
| */ |
| protected DfpDec(final DfpField factory, final String s) { |
| super(factory, s); |
| round(0); |
| } |
| |
| /** Creates an instance with a non-finite value. |
| * @param factory factory linked to this instance |
| * @param sign sign of the Dfp to create |
| * @param nans code of the value, must be one of {@link #INFINITE}, |
| * {@link #SNAN}, {@link #QNAN} |
| */ |
| protected DfpDec(final DfpField factory, final byte sign, final byte nans) { |
| super(factory, sign, nans); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance() { |
| return new DfpDec(getField()); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final byte x) { |
| return new DfpDec(getField(), x); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final int x) { |
| return new DfpDec(getField(), x); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final long x) { |
| return new DfpDec(getField(), x); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final double x) { |
| return new DfpDec(getField(), x); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final Dfp d) { |
| |
| // make sure we don't mix number with different precision |
| if (getField().getRadixDigits() != d.getField().getRadixDigits()) { |
| getField().setIEEEFlagsBits(DfpField.FLAG_INVALID); |
| final Dfp result = newInstance(getZero()); |
| result.nans = QNAN; |
| return dotrap(DfpField.FLAG_INVALID, "newInstance", d, result); |
| } |
| |
| return new DfpDec(d); |
| |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final String s) { |
| return new DfpDec(getField(), s); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp newInstance(final byte sign, final byte nans) { |
| return new DfpDec(getField(), sign, nans); |
| } |
| |
| /** Get the number of decimal digits this class is going to represent. |
| * Default implementation returns {@link #getRadixDigits()}*4-3. Subclasses can |
| * override this to return something less. |
| * @return number of decimal digits this class is going to represent |
| */ |
| protected int getDecimalDigits() { |
| return getRadixDigits() * 4 - 3; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected int round(int in) { |
| |
| int msb = mant[mant.length-1]; |
| if (msb == 0) { |
| // special case -- this == zero |
| return 0; |
| } |
| |
| int cmaxdigits = mant.length * 4; |
| int lsbthreshold = 1000; |
| while (lsbthreshold > msb) { |
| lsbthreshold /= 10; |
| cmaxdigits --; |
| } |
| |
| |
| final int digits = getDecimalDigits(); |
| final int lsbshift = cmaxdigits - digits; |
| final int lsd = lsbshift / 4; |
| |
| lsbthreshold = 1; |
| for (int i = 0; i < lsbshift % 4; i++) { |
| lsbthreshold *= 10; |
| } |
| |
| final int lsb = mant[lsd]; |
| |
| if (lsbthreshold <= 1 && digits == 4 * mant.length - 3) { |
| return super.round(in); |
| } |
| |
| int discarded = in; // not looking at this after this point |
| final int n; |
| if (lsbthreshold == 1) { |
| // look to the next digit for rounding |
| n = (mant[lsd-1] / 1000) % 10; |
| mant[lsd-1] %= 1000; |
| discarded |= mant[lsd-1]; |
| } else { |
| n = (lsb * 10 / lsbthreshold) % 10; |
| discarded |= lsb % (lsbthreshold/10); |
| } |
| |
| for (int i = 0; i < lsd; i++) { |
| discarded |= mant[i]; // need to know if there are any discarded bits |
| mant[i] = 0; |
| } |
| |
| mant[lsd] = lsb / lsbthreshold * lsbthreshold; |
| |
| final boolean inc; |
| switch (getField().getRoundingMode()) { |
| case ROUND_DOWN: |
| inc = false; |
| break; |
| |
| case ROUND_UP: |
| inc = (n != 0) || (discarded != 0); // round up if n!=0 |
| break; |
| |
| case ROUND_HALF_UP: |
| inc = n >= 5; // round half up |
| break; |
| |
| case ROUND_HALF_DOWN: |
| inc = n > 5; // round half down |
| break; |
| |
| case ROUND_HALF_EVEN: |
| inc = (n > 5) || |
| (n == 5 && discarded != 0) || |
| (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 1); // round half-even |
| break; |
| |
| case ROUND_HALF_ODD: |
| inc = (n > 5) || |
| (n == 5 && discarded != 0) || |
| (n == 5 && discarded == 0 && ((lsb / lsbthreshold) & 1) == 0); // round half-odd |
| break; |
| |
| case ROUND_CEIL: |
| inc = (sign == 1) && (n != 0 || discarded != 0); // round ceil |
| break; |
| |
| case ROUND_FLOOR: |
| default: |
| inc = (sign == -1) && (n != 0 || discarded != 0); // round floor |
| break; |
| } |
| |
| if (inc) { |
| // increment if necessary |
| int rh = lsbthreshold; |
| for (int i = lsd; i < mant.length; i++) { |
| final int r = mant[i] + rh; |
| rh = r / RADIX; |
| mant[i] = r % RADIX; |
| } |
| |
| if (rh != 0) { |
| shiftRight(); |
| mant[mant.length-1]=rh; |
| } |
| } |
| |
| // Check for exceptional cases and raise signals if necessary |
| if (exp < MIN_EXP) { |
| // Gradual Underflow |
| getField().setIEEEFlagsBits(DfpField.FLAG_UNDERFLOW); |
| return DfpField.FLAG_UNDERFLOW; |
| } |
| |
| if (exp > MAX_EXP) { |
| // Overflow |
| getField().setIEEEFlagsBits(DfpField.FLAG_OVERFLOW); |
| return DfpField.FLAG_OVERFLOW; |
| } |
| |
| if (n != 0 || discarded != 0) { |
| // Inexact |
| getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT); |
| return DfpField.FLAG_INEXACT; |
| } |
| return 0; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Dfp nextAfter(Dfp x) { |
| |
| final String trapName = "nextAfter"; |
| |
| // make sure we don't mix number with different precision |
| if (getField().getRadixDigits() != x.getField().getRadixDigits()) { |
| getField().setIEEEFlagsBits(DfpField.FLAG_INVALID); |
| final Dfp result = newInstance(getZero()); |
| result.nans = QNAN; |
| return dotrap(DfpField.FLAG_INVALID, trapName, x, result); |
| } |
| |
| boolean up = false; |
| Dfp result; |
| Dfp inc; |
| |
| // if this is greater than x |
| if (this.lessThan(x)) { |
| up = true; |
| } |
| |
| if (equals(x)) { |
| return newInstance(x); |
| } |
| |
| if (lessThan(getZero())) { |
| up = !up; |
| } |
| |
| if (up) { |
| inc = power10(log10() - getDecimalDigits() + 1); |
| inc = copysign(inc, this); |
| |
| if (this.equals(getZero())) { |
| inc = power10K(MIN_EXP-mant.length-1); |
| } |
| |
| if (inc.equals(getZero())) { |
| result = copysign(newInstance(getZero()), this); |
| } else { |
| result = add(inc); |
| } |
| } else { |
| inc = power10(log10()); |
| inc = copysign(inc, this); |
| |
| if (this.equals(inc)) { |
| inc = inc.divide(power10(getDecimalDigits())); |
| } else { |
| inc = inc.divide(power10(getDecimalDigits() - 1)); |
| } |
| |
| if (this.equals(getZero())) { |
| inc = power10K(MIN_EXP-mant.length-1); |
| } |
| |
| if (inc.equals(getZero())) { |
| result = copysign(newInstance(getZero()), this); |
| } else { |
| result = subtract(inc); |
| } |
| } |
| |
| if (result.classify() == INFINITE && this.classify() != INFINITE) { |
| getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT); |
| result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result); |
| } |
| |
| if (result.equals(getZero()) && this.equals(getZero()) == false) { |
| getField().setIEEEFlagsBits(DfpField.FLAG_INEXACT); |
| result = dotrap(DfpField.FLAG_INEXACT, trapName, x, result); |
| } |
| |
| return result; |
| } |
| |
| } |