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 18 package org.apache.commons.math.dfp; 19 20 /** Subclass of {@link Dfp} which hides the radix-10000 artifacts of the superclass. 21 * This should give outward appearances of being a decimal number with DIGITS*4-3 22 * decimal digits. This class can be subclassed to appear to be an arbitrary number 23 * of decimal digits less than DIGITS*4-3. 24 * @version $Revision: 1003892 $ $Date: 2010-10-02 23:28:56 +0200 (sam. 02 oct. 2010) $ 25 * @since 2.2 26 */ 27 public class DfpDec extends Dfp { 28 29 /** Makes an instance with a value of zero. 30 * @param factory factory linked to this instance 31 */ 32 protected DfpDec(final DfpField factory) { 33 super(factory); 34 } 35 36 /** Create an instance from a byte value. 37 * @param factory factory linked to this instance 38 * @param x value to convert to an instance 39 */ 40 protected DfpDec(final DfpField factory, byte x) { 41 super(factory, x); 42 } 43 44 /** Create an instance from an int value. 45 * @param factory factory linked to this instance 46 * @param x value to convert to an instance 47 */ 48 protected DfpDec(final DfpField factory, int x) { 49 super(factory, x); 50 } 51 52 /** Create an instance from a long 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, long x) { 57 super(factory, x); 58 } 59 60 /** Create an instance from a double value. 61 * @param factory factory linked to this instance 62 * @param x value to convert to an instance 63 */ 64 protected DfpDec(final DfpField factory, double x) { 65 super(factory, x); 66 round(0); 67 } 68 69 /** Copy constructor. 70 * @param d instance to copy 71 */ 72 public DfpDec(final Dfp d) { 73 super(d); 74 round(0); 75 } 76 77 /** Create an instance from a String representation. 78 * @param factory factory linked to this instance 79 * @param s string representation of the instance 80 */ 81 protected DfpDec(final DfpField factory, final String s) { 82 super(factory, s); 83 round(0); 84 } 85 86 /** Creates an instance with a non-finite value. 87 * @param factory factory linked to this instance 88 * @param sign sign of the Dfp to create 89 * @param nans code of the value, must be one of {@link #INFINITE}, 90 * {@link #SNAN}, {@link #QNAN} 91 */ 92 protected DfpDec(final DfpField factory, final byte sign, final byte nans) { 93 super(factory, sign, nans); 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 public Dfp newInstance() { 99 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 } 370