001/** 002 * The MIT License (MIT) 003 * 004 * Copyright (c) 2015-2016 decimal4j (tools4j), Marco Terzer 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in all 014 * copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 022 * SOFTWARE. 023 */ 024package org.decimal4j.arithmetic; 025 026import java.math.RoundingMode; 027 028import org.decimal4j.api.DecimalArithmetic; 029import org.decimal4j.scale.Scale18f; 030import org.decimal4j.scale.Scale8f; 031import org.decimal4j.scale.Scale9f; 032import org.decimal4j.scale.ScaleMetrics; 033import org.decimal4j.scale.Scales; 034import org.decimal4j.truncate.DecimalRounding; 035import org.decimal4j.truncate.OverflowMode; 036import org.decimal4j.truncate.TruncatedPart; 037 038/** 039 * Helper class for an unsigned decimal value with 9 integral digits and 38 decimal 040 * fraction digits used internally by {@link Pow} to calculate decimal powers. 041 */ 042final class UnsignedDecimal9i36f { 043 /** Thread local for factor 1*/ 044 static final ThreadLocal<UnsignedDecimal9i36f> THREAD_LOCAL_1 = new ThreadLocal<UnsignedDecimal9i36f>() { 045 @Override 046 protected UnsignedDecimal9i36f initialValue() { 047 return new UnsignedDecimal9i36f(); 048 } 049 }; 050 /** Thread local for accumulator*/ 051 static final ThreadLocal<UnsignedDecimal9i36f> THREAD_LOCAL_2 = new ThreadLocal<UnsignedDecimal9i36f>() { 052 @Override 053 protected UnsignedDecimal9i36f initialValue() { 054 return new UnsignedDecimal9i36f(); 055 } 056 }; 057 058 /** 059 * Normalization mode. 060 */ 061 private static enum Norm { 062 /** Not normalized: ival and valX can be any positive longs */ 063 UNNORMALIZED, 064 /** 18 digit normalization (standard): ival is 9 digits; val3/val2 are 18 digits, val1/val0 are zero*/ 065 NORMALIZED_18, 066 /** 9 digit normalization (for multiplication): ival and valX are 9 digits values*/ 067 NORMALIZED_09 068 } 069 private Norm norm; 070 private int pow10; 071 private long ival; 072 private long val3; 073 private long val2; 074 private long val1; 075 private long val0; 076 077 /** Constructor */ 078 private UnsignedDecimal9i36f() { 079 super(); 080 } 081 082 /** 083 * Assigns the value one to this unsigned 9x36 decimal and returns it. 084 * 085 * @return this 086 */ 087 public final UnsignedDecimal9i36f initOne() { 088 this.norm = Norm.NORMALIZED_18; 089 this.pow10 = 0; 090 this.ival = 1; 091 this.val3 = 0; 092 this.val2 = 0; 093 this.val1 = 0; 094 this.val0 = 0; 095 return this; 096 } 097 098 /** 099 * Assigns the value one to this unsigned 9x36 decimal and returns it. 100 * 101 * @param copy 102 * the value to copy 103 * @return this 104 */ 105 public final UnsignedDecimal9i36f init(UnsignedDecimal9i36f copy) { 106 this.norm = copy.norm; 107 this.pow10 = copy.pow10; 108 this.ival = copy.ival; 109 this.val3 = copy.val3; 110 this.val2 = copy.val2; 111 this.val1 = copy.val1; 112 this.val0 = copy.val0; 113 return this; 114 } 115 116 /** 117 * Assigns the given integer and fraction component to this unsigned 9x36 118 * decimal and returns it. 119 * 120 * @param ival 121 * the integer part of the value to assign 122 * @param fval 123 * the fractional part of the value to assign 124 * @param scaleMetrics 125 * the scale metrics associated with the value 126 * @return this 127 */ 128 public final UnsignedDecimal9i36f init(long ival, long fval, ScaleMetrics scaleMetrics) { 129 final ScaleMetrics diffMetrics = Scales.getScaleMetrics(18 - scaleMetrics.getScale()); 130 normalizeAndRound(1, 0, ival, diffMetrics.multiplyByScaleFactor(fval), 0, 0, 0, DecimalRounding.UNNECESSARY); 131 return this; 132 } 133 134 /** 135 * Returns the current power-ten exponent. 136 * 137 * @return the base-10 exponent of this value 138 */ 139 public final int getPow10() { 140 return pow10; 141 } 142 private final void normalizeAndRound(int sgn, int pow10, long ival, long val3, long val2, long val1, long val0, DecimalRounding rounding) { 143 while (ival == 0) { 144 ival = val3; 145 val3 = val2; 146 val2 = val1; 147 val1 = val0; 148 val0 = 0; 149 pow10 -= 18; 150 } 151 if (ival >= Scale9f.SCALE_FACTOR) { 152 long carry; 153 154 final int log10 = log10(ival); 155 final int div10 = log10 - 9; 156 final ScaleMetrics divScale = Scales.getScaleMetrics(div10); 157 final ScaleMetrics mulScale = Scales.getScaleMetrics(18 - div10); 158 159 final long ivHi = divScale.divideByScaleFactor(ival); 160 final long ivLo = ival - divScale.multiplyByScaleFactor(ivHi); 161 ival = ivHi; 162 carry = mulScale.multiplyByScaleFactor(ivLo); 163 164 if (val3 != 0) { 165 final long v3Hi = divScale.divideByScaleFactor(val3); 166 final long v3Lo = val3 - divScale.multiplyByScaleFactor(v3Hi); 167 val3 = v3Hi + carry; 168 carry = mulScale.multiplyByScaleFactor(v3Lo); 169 } else { 170 val3 = carry; 171 carry = 0; 172 } 173 174 if (val2 != 0) { 175 final long v2Hi = divScale.divideByScaleFactor(val2); 176 final long v2Lo = val2 - divScale.multiplyByScaleFactor(v2Hi); 177 val2 = v2Hi + carry; 178 carry = mulScale.multiplyByScaleFactor(v2Lo); 179 } else { 180 val2 = carry; 181 carry = 0; 182 } 183 184 if (val1 != 0) { 185 final long v1Hi = divScale.divideByScaleFactor(val1); 186 final long v1Lo = val1 - divScale.multiplyByScaleFactor(v1Hi); 187 val1 = v1Hi + carry; 188 carry = mulScale.multiplyByScaleFactor(v1Lo); 189 } else { 190 val1 = carry; 191 carry = 0; 192 } 193 roundToVal2(sgn, pow10 + div10, ival, val3, val2, val1, val0 != 0 | carry != 0, rounding); 194 } else { 195 roundToVal2(sgn, pow10, ival, val3, val2, val1, val0 != 0, rounding); 196 } 197 } 198 private final void roundToVal2(int sgn, int pow10, long ival, long val3, long val2, long val1, boolean nonZeroAfterVal1, DecimalRounding rounding) { 199 //(ival|val3|val2) += round(val1|val0|carry) 200 final int inc = getRoundingIncrement(sgn, val2, Scale18f.INSTANCE, val1, nonZeroAfterVal1, rounding); 201 if (inc > 0) { 202 val2++; 203 if (val2 >= Scale18f.SCALE_FACTOR) { 204 val2 = 0;//val2 -= Scale18f.SCALE_FACTOR; 205 val3++; 206 if (val3 >= Scale18f.SCALE_FACTOR) { 207 val3 = 0;//val3 -= Scale18f.SCALE_FACTOR; 208 ival++; 209 if (ival >= Scale9f.SCALE_FACTOR) { 210 ival = Scale8f.SCALE_FACTOR;//ival /= 10 211 pow10++; 212 } 213 } 214 } 215 } 216 this.norm = Norm.NORMALIZED_18; 217 this.pow10 = pow10; 218 this.ival = ival; 219 this.val3 = val3; 220 this.val2 = val2; 221 this.val1 = 0; 222 this.val0 = 0; 223 } 224 private final void normalize09() { 225 final long val3 = this.val3; 226 final long val2 = this.val2; 227 final long v3 = val3 / Scale9f.SCALE_FACTOR; 228 final long v2 = val3 - v3 * Scale9f.SCALE_FACTOR; 229 final long v1 = val2 / Scale9f.SCALE_FACTOR; 230 final long v0 = val2 - v1 * Scale9f.SCALE_FACTOR; 231 this.norm = Norm.NORMALIZED_09; 232 this.val3 = v3; 233 this.val2 = v2; 234 this.val1 = v1; 235 this.val0 = v0; 236 } 237 238 /** 239 * Multiplies this unsigned 9x36 decimal value with another one. 240 * 241 * @param sgn 242 * the sign of the final result 243 * @param factor 244 * the factor to be multiplied with 245 * @param rounding 246 * the rounding to apply 247 */ 248 public final void multiply(int sgn, UnsignedDecimal9i36f factor, DecimalRounding rounding) { 249 if (norm != Norm.NORMALIZED_18) { 250 normalizeAndRound(sgn, pow10, ival, val3, val2, val1, val0, rounding); 251 } 252 multiply(sgn, val3, val2, factor, rounding); 253 } 254 //PRECONDITION: this and factor normalized, i.e. ival < Scale9f.SCALE_FACTOR 255 private final void multiply(int sgn, long val3, long val2, UnsignedDecimal9i36f factor, DecimalRounding rounding) { 256 //split each factor into 9 digit parts 257 if (this.norm != Norm.NORMALIZED_09) { 258 this.normalize09(); 259 } 260 final long lhs4 = this.ival; 261 final long lhs3 = this.val3; 262 final long lhs2 = this.val2; 263 final long lhs1 = this.val1; 264 final long lhs0 = this.val0; 265 if (factor.norm != Norm.NORMALIZED_09) { 266 factor.normalize09(); 267 } 268 final long rhs4 = factor.ival; 269 final long rhs3 = factor.val3; 270 final long rhs2 = factor.val2; 271 final long rhs1 = factor.val1; 272 final long rhs0 = factor.val0; 273 274 //multiply now 275 long scale72 = lhs0 * rhs0; 276 long scale63 = lhs1 * rhs0 + rhs1 * lhs0; 277 long scale54 = lhs2 * rhs0 + rhs2 * lhs0 + lhs1 * rhs1; 278 long scale45 = lhs3 * rhs0 + rhs3 * lhs0 + lhs2 * rhs1 + rhs2 * lhs1; 279 long scale36 = lhs3 * rhs1 + rhs3 * lhs1 + lhs2 * rhs2 + lhs0 * rhs4 + rhs0 * lhs4; 280 long scale27 = lhs3 * rhs2 + rhs3 * lhs2 + lhs1 * rhs4 + rhs1 * lhs4; 281 long scale18 = lhs3 * rhs3 + lhs2 * rhs4 + rhs2 * lhs4; 282 long scale09 = lhs3 * rhs4 + rhs3 * lhs4; 283 long scale00 = lhs4 * rhs4; 284 285 //reduce 8 to 4 parts and propagate carries 286 long carry; 287 288 //NOTE: largest value is val36: sum of 5 products + sum of 4 products 289 // -- each product consists of 2 factors < Scale9f.SCALE_FACTOR 290 // -- hence each product < Scale18f.SCALE_FACTOR 291 // -- sum of 9 products each < Scale18f.SCALE_FACTOR 292 // => sum < 9 * Scale18f.SCALE_FACTOR < Long.MAX_VALUE 293 // => no overflows 294 295 carry = scale63 / Scale9f.SCALE_FACTOR; 296 scale63 -= carry * Scale9f.SCALE_FACTOR; 297 long val72 = scale63 * Scale9f.SCALE_FACTOR + scale72; 298 while (val72 >= Scale18f.SCALE_FACTOR) { 299 val72 -= Scale18f.SCALE_FACTOR; 300 carry++; 301 } 302 scale54 += carry; 303 304 carry = scale45 / Scale9f.SCALE_FACTOR; 305 scale45 -= carry * Scale9f.SCALE_FACTOR; 306 long val54 = scale45 * Scale9f.SCALE_FACTOR + scale54; 307 while (val54 >= Scale18f.SCALE_FACTOR) { 308 val54 -= Scale18f.SCALE_FACTOR; 309 carry++; 310 } 311 scale36 += carry; 312 313 carry = scale27 / Scale9f.SCALE_FACTOR; 314 scale27 -= carry * Scale9f.SCALE_FACTOR; 315 long val36 = scale27 * Scale9f.SCALE_FACTOR + scale36; 316 while (val36 >= Scale18f.SCALE_FACTOR) { 317 val36 -= Scale18f.SCALE_FACTOR; 318 carry++; 319 } 320 scale18 += carry; 321 322 carry = scale09 / Scale9f.SCALE_FACTOR; 323 scale09 -= carry * Scale9f.SCALE_FACTOR; 324 long val18 = scale09 * Scale9f.SCALE_FACTOR + scale18; 325 while (val18 >= Scale18f.SCALE_FACTOR) { 326 val18 -= Scale18f.SCALE_FACTOR; 327 carry++; 328 } 329 scale00 += carry; 330 331 //assign values 332 this.norm = Norm.UNNORMALIZED; 333 this.pow10 += factor.pow10; 334 this.ival = scale00; 335 this.val3 = val18; 336 this.val2 = val36; 337 this.val1 = val54; 338 this.val0 = val72; 339 } 340 341 private static final int getRoundingIncrement(int sgn, long truncated, ScaleMetrics scaleMetrics, long remainder, boolean nonZeroAfterRemainder, DecimalRounding rounding) { 342 if (rounding != DecimalRounding.DOWN & (remainder != 0 | nonZeroAfterRemainder)) { 343 TruncatedPart truncatedPart = Rounding.truncatedPartFor(remainder, scaleMetrics.getScaleFactor()); 344 if (nonZeroAfterRemainder) { 345 if (truncatedPart == TruncatedPart.ZERO) truncatedPart = TruncatedPart.LESS_THAN_HALF_BUT_NOT_ZERO; 346 else if (truncatedPart == TruncatedPart.EQUAL_TO_HALF) truncatedPart = TruncatedPart.GREATER_THAN_HALF; 347 } 348 return getRoundingIncrement(sgn, truncated, rounding, truncatedPart); 349 } 350 return 0; 351 } 352 private static final int getRoundingIncrement(int sgn, long absValue, DecimalRounding rounding, TruncatedPart truncatedPart) { 353 if (sgn < 0) { 354 return -rounding.calculateRoundingIncrement(-1, -absValue, truncatedPart); 355 } else { 356 return rounding.calculateRoundingIncrement(1, absValue, truncatedPart); 357 } 358 } 359 private final int getInvNormPow10() { 360 final int log10 = log10(ival); 361 return (ival >= Scales.getScaleMetrics(log10 - 1).getScaleFactor()*3) ? log10 : log10 - 1;//we want to normalize the ival part to be between 1 and 5 362 } 363 private final long getInvNorm(int sgn, DecimalArithmetic arith, DecimalRounding rounding) { 364 final int pow10 = -getInvNormPow10(); 365 if (pow10 >= 0) { 366 return getDecimal(sgn, pow10, ival, val3, val2, val1, val0, 0, 0, 0, 0, arith, rounding); 367 } 368 return getDecimal(sgn, pow10 + 18, 0, ival, val3, val2, val1, val0, 0, 0, 0, arith, rounding); 369 } 370 371 /** 372 * Returns the inverted result resulting from exponentiation with a negative 373 * exponent. The result is best-effort accurate. 374 * 375 * @param sgn 376 * the sign of the final result 377 * @param arith 378 * the arithmetic of the base value 379 * @param rounding 380 * the rounding to apply 381 * @param powRounding 382 * reciprocal rounding if exponent is negative and rounding 383 * otherwise 384 * @return <tt>round(1 / this)</tt> 385 */ 386 public final long getInverted(int sgn, DecimalArithmetic arith, DecimalRounding rounding, DecimalRounding powRounding) { 387 //1) get scale18 value normalized to 0.3 <= x < 3 (i.e. make it invertible without overflow for uninverted and inverted value) 388 final DecimalArithmetic arith18 = Scale18f.INSTANCE.getArithmetic(rounding.getRoundingMode());//unchecked is fine, see comments below 389 final long divisor = this.getInvNorm(sgn, arith18, powRounding); 390 //2) invert normalized scale18 value 391 final long inverted = arith18.invert(divisor);//can't overflow as for x=abs(divisor): 0.9 <= x < 9 392 //3) apply inverted powers of 10, including powers from normalization and rescaling 393 final int pow10 = this.getPow10() + this.getInvNormPow10() + (18 - arith.getScale()); 394 return arith.multiplyByPowerOf10(inverted, -pow10);//overflow possible 395 } 396 397 /** 398 * Returns the unscaled Decimal result resulting from exponentiation with a non-negative 399 * exponent. The result is accurate up to 1 ULP of the Decimal. 400 * 401 * @param sgn 402 * the sign of the final result 403 * @param arith 404 * the arithmetic of the base value 405 * @param rounding 406 * the rounding to apply 407 * @return <tt>round(this)</tt> 408 */ 409 public final long getDecimal(int sgn, DecimalArithmetic arith, DecimalRounding rounding) { 410 if (pow10 >= 0) { 411 if (pow10 <= 18) { 412 return getDecimal(sgn, pow10, ival, val3, val2, val1, val0, 0, 0, 0, 0, arith, rounding); 413 } 414 if (arith.getOverflowMode().isChecked()) { 415 return checkedMultiplyByPowerOf10AndRound(sgn, arith, rounding); 416 } 417 return multiplyByPowerOf10AndRound(sgn, arith, rounding); 418 } else { 419 return divideByPowerOf10AndRound(sgn, arith, rounding); 420 } 421 } 422 private final long multiplyByPowerOf10AndRound(int sgn, DecimalArithmetic arith, DecimalRounding rounding) { 423 long iv = ival * Scale18f.SCALE_FACTOR + val3; 424 if (pow10 <= 36) { 425 return getDecimal(sgn, pow10 - 18, iv, val2, val1, val0, 0, 0, 0, 0, 0, arith, rounding); 426 } 427 iv *= Scale18f.SCALE_FACTOR + val2; 428 if (pow10 <= 54) { 429 return getDecimal(sgn, pow10 - 36, iv, val1, val0, 0, 0, 0, 0, 0, 0, arith, rounding); 430 } 431 iv *= Scale18f.SCALE_FACTOR + val1; 432 if (pow10 <= 72) { 433 return getDecimal(sgn, pow10 - 54, iv, val0, 0, 0, 0, 0, 0, 0, 0, arith, rounding); 434 } 435 iv *= Scale18f.SCALE_FACTOR + val0; 436 int pow = pow10 - 72; 437 while (pow > 18 & iv != 0) { 438 iv *= Scale18f.SCALE_FACTOR; 439 pow -= 18; 440 } 441 if (iv != 0) { 442 final long absVal = arith.fromLong(iv); 443 return sgn >= 0 ? absVal : -absVal; 444 } 445 return 0;//overflow, everything was shifted out to the left 446 } 447 private final long checkedMultiplyByPowerOf10AndRound(int sgn, DecimalArithmetic arith, DecimalRounding rounding) { 448 final DecimalArithmetic arith18 = Scale18f.INSTANCE.getCheckedArithmetic(RoundingMode.DOWN); 449 long iv = arith18.add(arith18.fromLong(ival), val3);//ival * 10^18 + val3 450 if (pow10 <= 36) { 451 return getDecimal(sgn, pow10 - 18, iv, val2, val1, val0, 0, 0, 0, 0, 0, arith, rounding); 452 } 453 iv = arith18.add(arith18.fromLong(iv), val2);//iv * 10^18 + val2 454 if (pow10 <= 54) { 455 return getDecimal(sgn, pow10 - 36, iv, val1, val0, 0, 0, 0, 0, 0, 0, arith, rounding); 456 } 457 iv = arith18.add(arith18.fromLong(iv), val1);//iv * 10^18 + val1 458 if (pow10 <= 72) { 459 return getDecimal(sgn, pow10 - 54, iv, val0, 0, 0, 0, 0, 0, 0, 0, arith, rounding); 460 } 461 iv = arith18.add(arith18.fromLong(iv), val0);//iv * 10^18 + val0 462 int pow = pow10 - 72; 463 while (pow > 18 & iv != 0) { 464 iv = arith18.fromLong(iv);//iv * 10^18 465 pow -= 18; 466 } 467 if (iv != 0) { 468 final long absVal = arith.fromLong(iv); 469 return sgn >= 0 ? absVal : arith.negate(absVal); 470 } 471 //should not get here, an overflow exception should have been thrown 472 return 0;//overflow, everything was shifted out to the left 473 } 474 private final long divideByPowerOf10AndRound(int sgn, DecimalArithmetic arith, DecimalRounding rounding) { 475 if (pow10 >= -18) { 476 return getDecimal(sgn, pow10 + 18, 0, ival, val3, val2, val1, val0, 0, 0, 0, arith, rounding); 477 } else if (pow10 >= -36) { 478 return getDecimal(sgn, pow10 + 36, 0, 0, ival, val3, val2, val1, val0, 0, 0, arith, rounding); 479 } else { 480 //only rounding left 481 if (rounding != DecimalRounding.DOWN & (ival != 0 | val3 != 0 | val2 != 0 | val1 != 0 | val0 != 0)) { 482 return rounding.calculateRoundingIncrement(sgn, 0, TruncatedPart.LESS_THAN_HALF_BUT_NOT_ZERO); 483 } 484 return 0; 485 } 486 } 487 //PRECONDITION: 0 <= pow10 <= 18 488 private static final long getDecimal(int sgn, int pow10, long ival, long val3, long val2, long val1, long val0, long rem1, long rem2, long rem3, long rem4, DecimalArithmetic arith, DecimalRounding rounding) { 489 final OverflowMode overflowMode = arith.getOverflowMode(); 490 491 //apply pow10 first and convert to intVal and fra18 (with scale 18, w/o rounding) 492 final long int18; 493 final long fra18; 494 final long rem18; 495 if (pow10 > 0) { 496 final ScaleMetrics mul10Scale = Scales.getScaleMetrics(pow10); 497 final ScaleMetrics div10Scale = Scales.getScaleMetrics(18 - pow10); 498 final long hiVal3 = div10Scale.divideByScaleFactor(val3); 499 final long loVal3 = val3 - div10Scale.multiplyByScaleFactor(hiVal3); 500 final long hiVal2 = div10Scale.divideByScaleFactor(val2); 501 final long loVal2 = val2 - div10Scale.multiplyByScaleFactor(hiVal2); 502 int18 = add(mulByScaleFactor(mul10Scale, ival, overflowMode), hiVal3, overflowMode);//overflow possible (2x) 503 fra18 = mul10Scale.multiplyByScaleFactor(loVal3) + hiVal2;//cannot overflow because it is < 1 504 rem18 = loVal2; 505 } else { 506 int18 = ival; 507 fra18 = val3; 508 rem18 = val2; 509 } 510 511 //apply scale now this time with rounding 512 final ScaleMetrics diffMetrics = Scales.getScaleMetrics(18 - arith.getScale()); 513 final long fraVal = diffMetrics.divideByScaleFactor(fra18); 514 final long fraRem = fra18 - diffMetrics.multiplyByScaleFactor(fraVal); 515 final int inc = getRoundingIncrement(sgn, fraVal, diffMetrics, fraRem, rem18 != 0 | val1 != 0 | val0 != 0 | rem1 != 0 | rem2 != 0 | rem3 != 0 | rem4 != 0, rounding); 516 final long fraRnd = fraVal + inc;//cannot overflow because it is <= 1 517 final long absVal = add(arith.fromLong(int18), fraRnd, overflowMode);//overflow possible (2x) 518 return sgn >= 0 ? absVal : arith.negate(absVal); 519 } 520 521 private static final long add(long l1, long l2, OverflowMode overflowMode) { 522 return overflowMode == OverflowMode.UNCHECKED ? l1 + l2 : Checked.addLong(l1, l2); 523 } 524 private static final long mulByScaleFactor(ScaleMetrics scaleMetrics, long val, OverflowMode overflowMode) { 525 return val == 0 ? 0 : overflowMode == OverflowMode.UNCHECKED ? scaleMetrics.multiplyByScaleFactor(val) : scaleMetrics.multiplyByScaleFactorExact(val); 526 } 527 528 private static final long[] LONG_TEN_POWERS_TABLE = { 529 1, // 0 / 10^0 530 10, // 1 / 10^1 531 100, // 2 / 10^2 532 1000, // 3 / 10^3 533 10000, // 4 / 10^4 534 100000, // 5 / 10^5 535 1000000, // 6 / 10^6 536 10000000, // 7 / 10^7 537 100000000, // 8 / 10^8 538 1000000000, // 9 / 10^9 539 10000000000L, // 10 / 10^10 540 100000000000L, // 11 / 10^11 541 1000000000000L, // 12 / 10^12 542 10000000000000L, // 13 / 10^13 543 100000000000000L, // 14 / 10^14 544 1000000000000000L, // 15 / 10^15 545 10000000000000000L, // 16 / 10^16 546 100000000000000000L, // 17 / 10^17 547 1000000000000000000L // 18 / 10^18 548 }; 549 /** 550 * Returns the length of the absolute value of a {@code long}, in decimal 551 * digits. 552 * 553 * @param absVal the {@code long} 554 * @return the length of the unscaled value, in deciaml digits. 555 */ 556 private static final int log10(long absVal) { 557 /* 558 * As described in "Bit Twiddling Hacks" by Sean Anderson, 559 * (http://graphics.stanford.edu/~seander/bithacks.html) 560 * integer log 10 of x is within 1 of (1233/4096)* (1 + 561 * integer log 2 of x). The fraction 1233/4096 approximates 562 * log10(2). So we first do a version of log2 (a variant of 563 * Long class with pre-checks and opposite directionality) and 564 * then scale and check against powers table. This is a little 565 * simpler in present context than the version in Hacker's 566 * Delight sec 11-4. Adding one to bit length allows comparing 567 * downward from the LONG_TEN_POWERS_TABLE that we need 568 * anyway. 569 */ 570 if (absVal < 10) // must screen for 0, might as well 10 571 return 1; 572 final int r = ((64 - Long.numberOfLeadingZeros(absVal) + 1) * 1233) >>> 12; 573 final long[] tab = LONG_TEN_POWERS_TABLE; 574 // if r >= length, must have max possible digits for long 575 return (r >= tab.length || absVal < tab[r]) ? r : r + 1; 576 } 577 @Override 578 public final String toString() { 579 int len; 580 final StringBuilder sb = new StringBuilder(64);//9-18 integral digits + 1 decimal point + 2*18 fractional digits + some extra for pow10 etc 581 sb.append(ival); 582 sb.append('.'); 583 len = sb.length(); 584 sb.append(val3); 585 sb.insert(len, "000000000000000000", 0, len + 18 - sb.length()); 586 len = sb.length(); 587 sb.append(val2); 588 sb.insert(len, "000000000000000000", 0, len + 18 - sb.length()); 589 if (val1 != 0 | val0 != 0) { 590 sb.append(".."); 591 } 592 sb.append("*10^").append(pow10); 593 return sb.toString(); 594 } 595 596}