001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2023 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 <code>round(1 / this)</code>
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 <code>round(this)</code>
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}