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