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 org.decimal4j.api.DecimalArithmetic;
027import org.decimal4j.scale.ScaleMetrics;
028import org.decimal4j.scale.Scales;
029import org.decimal4j.truncate.DecimalRounding;
030import org.decimal4j.truncate.TruncatedPart;
031
032/**
033 * Provides static methods to calculate division results.
034 */
035final class Div {
036
037        private static final long LONG_MASK = 0xffffffffL;
038
039        /**
040         * Calculates unchecked division by a long value with rounding.
041         * 
042         * @param rounding
043         *            the decimal rounding to apply if rounding is necessary
044         * @param uDecimalDividend
045         *            the unscaled decimal dividend
046         * @param lDivisor
047         *            the long divisor
048         * @return the division result with rounding and no overflow checks
049         */
050        public static final long divideByLong(DecimalRounding rounding, long uDecimalDividend, long lDivisor) {
051                final long quotient = uDecimalDividend / lDivisor;
052                final long remainder = uDecimalDividend - quotient * lDivisor;
053                return quotient + Rounding.calculateRoundingIncrementForDivision(rounding, quotient, remainder, lDivisor);
054        }
055
056        /**
057         * Calculates checked division by a long value with rounding.
058         * 
059         * @param arith
060         *            the arithmetic used to format numbers when throwing exceptions
061         * @param rounding
062         *            the decimal rounding to apply if rounding is necessary
063         * @param uDecimalDividend
064         *            the unscaled decimal dividend
065         * @param lDivisor
066         *            the long divisor
067         * @return the division result with rounding and overflow checks
068         */
069        public static final long divideByLongChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimalDividend, long lDivisor) {
070                if (lDivisor == 0) {
071                        throw new ArithmeticException("Division by zero: " + arith.toString(uDecimalDividend) + " / " + lDivisor);
072                }
073                try {
074                        final long quotient = Checked.divideByLong(arith, uDecimalDividend, lDivisor);
075                        final long remainder = uDecimalDividend - quotient * lDivisor;
076                        final long inc = Rounding.calculateRoundingIncrementForDivision(rounding, quotient, remainder, lDivisor);
077                        return Checked.add(arith, quotient, inc);
078                } catch (ArithmeticException e) {
079                        Exceptions.rethrowIfRoundingNecessary(e);
080                        throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + arith.toString(uDecimalDividend) + " / "
081                                        + lDivisor, e);
082                }
083        }
084
085        /**
086         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
087         * without rounding and overflow checks.
088         * 
089         * @param arith
090         *            the arithmetic with scale metrics and overflow mode
091         * @param uDecimalDividend
092         *            the unscaled decimal dividend
093         * @param uDecimalDivisor
094         *            the unscaled decimal divisor
095         * @return the division result without rounding and without overflow checks.
096         */
097        public static final long divide(DecimalArithmetic arith, long uDecimalDividend, long uDecimalDivisor) {
098                // special cases first
099                final SpecialDivisionResult special = SpecialDivisionResult.getFor(arith, uDecimalDividend, uDecimalDivisor);
100                if (special != null) {
101                        return special.divide(arith, uDecimalDividend, uDecimalDivisor);
102                }
103                // div by power of 10
104                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
105                final ScaleMetrics pow10 = Scales.findByScaleFactor(Math.abs(uDecimalDivisor));
106                if (pow10 != null) {
107                        return Pow10.divideByPowerOf10(uDecimalDividend, scaleMetrics, uDecimalDivisor > 0, pow10);
108                }
109                return divide(uDecimalDividend, scaleMetrics, uDecimalDivisor);
110        }
111
112        /**
113         * Calculates unchecked division by an unscaled value with the given scale
114         * without rounding and overflow checks.
115         * 
116         * @param uDecimalDividend
117         *            the unscaled decimal dividend
118         * @param unscaledDivisor
119         *            the long divisor
120         * @param scale
121         *            the scale of the divisor
122         * @return the division result without rounding and without overflow checks
123         */
124        public static final long divideByUnscaled(long uDecimalDividend, long unscaledDivisor, int scale) {
125                if (scale > Scales.MAX_SCALE) {
126                        throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale);
127                }
128                if (unscaledDivisor == 0 | scale == 0) {
129                        return uDecimalDividend / unscaledDivisor;
130                } else if (scale < 0) {
131                        if (Checked.isDivideOverflow(uDecimalDividend, unscaledDivisor)) {
132                                return -Pow10.multiplyByPowerOf10(uDecimalDividend, scale);
133                        }
134                        return Pow10.multiplyByPowerOf10(uDecimalDividend / unscaledDivisor, scale);
135                }
136                final ScaleMetrics divisorMetrics = Scales.getScaleMetrics(scale);
137                return divide(uDecimalDividend, divisorMetrics, unscaledDivisor);
138        }
139
140        /**
141         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
142         * without rounding and overflow checks.
143         * 
144         * @param uDecimalDividend
145         *            the unscaled decimal dividend
146         * @param divisorMetrics
147         *            the metrics associated with the divisor
148         * @param uDecimalDivisor
149         *            the unscaled decimal divisor
150         * @return the division result without rounding and without overflow checks.
151         */
152        private static final long divide(long uDecimalDividend, ScaleMetrics divisorMetrics, long uDecimalDivisor) {
153                // WE WANT: uDecimalDividend * 10^scale / unscaledDivisor
154                if (divisorMetrics.isValidIntegerValue(uDecimalDividend)) {
155                        // just do it, multiplication result fits in long
156                        return divisorMetrics.multiplyByScaleFactor(uDecimalDividend) / uDecimalDivisor;
157                }
158                if (divisorMetrics.isValidIntegerValue(uDecimalDivisor)) {
159                        // perform component wise division (reminder fits in long after scaling)
160                        final long integralPart = uDecimalDividend / uDecimalDivisor;
161                        final long remainder = uDecimalDividend - integralPart * uDecimalDivisor;
162                        final long fractionalPart = divisorMetrics.multiplyByScaleFactor(remainder) / uDecimalDivisor;
163                        return divisorMetrics.multiplyByScaleFactor(integralPart) + fractionalPart;
164                }
165                return scaleTo128divBy64(divisorMetrics, DecimalRounding.DOWN, uDecimalDividend, uDecimalDivisor);
166        }
167
168        /**
169         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
170         * with rounding and without overflow checks.
171         * 
172         * @param arith
173         *            the arithmetic with scale metrics and overflow mode
174         * @param rounding
175         *            the decimal rounding to apply if rounding is necessary
176         * @param uDecimalDividend
177         *            the unscaled decimal dividend
178         * @param uDecimalDivisor
179         *            the unscaled decimal divisor
180         * @return the division result with rounding and without overflow checks
181         */
182        public static final long divide(DecimalArithmetic arith, DecimalRounding rounding, long uDecimalDividend, long uDecimalDivisor) {
183                // special cases first
184                final SpecialDivisionResult special = SpecialDivisionResult.getFor(arith, uDecimalDividend, uDecimalDivisor);
185                if (special != null) {
186                        return special.divide(arith, uDecimalDividend, uDecimalDivisor);
187                }
188                // div by power of 10
189                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
190                final ScaleMetrics pow10 = Scales.findByScaleFactor(Math.abs(uDecimalDivisor));
191                if (pow10 != null) {
192                        return Pow10.divideByPowerOf10(rounding, uDecimalDividend, scaleMetrics, uDecimalDivisor > 0, pow10);
193                }
194                return divide(rounding, uDecimalDividend, scaleMetrics, uDecimalDivisor);
195        }
196
197        /**
198         * Calculates unchecked division by an unscaled value with the given scale
199         * without rounding.
200         * 
201         * @param rounding
202         *            the rounding to apply
203         * @param uDecimalDividend
204         *            the unscaled decimal dividend
205         * @param unscaledDivisor
206         *            the long divisor
207         * @param scale
208         *            the scale of the divisor
209         * @return the division result without rounding and without overflow checks
210         */
211        public static final long divideByUnscaled(DecimalRounding rounding, long uDecimalDividend, long unscaledDivisor, int scale) {
212                if (scale > Scales.MAX_SCALE) {
213                        throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale);
214                }
215                if (unscaledDivisor == 0 | scale == 0) {
216                        return divideByLong(rounding, uDecimalDividend, unscaledDivisor);
217                } else if (scale < 0) {
218                        if (Checked.isDivideOverflow(uDecimalDividend, unscaledDivisor)) {
219                                return -Pow10.multiplyByPowerOf10(RoundingInverse.SIGN_REVERSION.invert(rounding), uDecimalDividend, scale);
220                        }
221                        //NOTE: rounding twice could be a problem here, e.g. consider HALF_UP with 10.51 and 10.49
222                        final long quot;
223                        switch (rounding) {
224                        case HALF_UP:
225                                quot = uDecimalDividend / unscaledDivisor;//DOWN
226                                break;
227                        case HALF_DOWN:
228                                quot = divideByLong(DecimalRounding.UP, uDecimalDividend, unscaledDivisor);
229                                break;
230                        case HALF_EVEN: {
231                                //try HALF_UP first
232                                final long quotD = uDecimalDividend / unscaledDivisor;//DOWN
233                                final long powHU = Pow10.multiplyByPowerOf10(DecimalRounding.HALF_UP, quotD, scale);
234                                if (0 == (powHU & 0x1)) {
235                                        //even, we're done
236                                        return powHU;
237                                }
238                                //odd, HALF_DOWN may be even in which case it should win
239                                final long quotU = divideByLong(DecimalRounding.UP, uDecimalDividend, unscaledDivisor);
240                                final long powHD = Pow10.multiplyByPowerOf10(DecimalRounding.HALF_DOWN, quotU, scale);
241                                return powHD;//either even or the same as powHU
242                        }
243                        default:
244                                quot = divideByLong(rounding, uDecimalDividend, unscaledDivisor);
245                                break;
246                        }
247                        return Pow10.multiplyByPowerOf10(rounding, quot, scale);
248                }
249                final ScaleMetrics divisorMetrics = Scales.getScaleMetrics(scale);
250                return divide(rounding, uDecimalDividend, divisorMetrics, unscaledDivisor);
251        }
252
253        /**
254         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
255         * with rounding and without overflow checks.
256         * 
257         * @param rounding
258         *            the decimal rounding to apply if rounding is necessary
259         * @param uDecimalDividend
260         *            the unscaled decimal dividend
261         * @param divisorMetrics
262         *            the metrics associated with the divisor
263         * @param uDecimalDivisor
264         *            the unscaled decimal divisor
265         * @return the division result with rounding and without overflow checks
266         */
267        private static final long divide(DecimalRounding rounding, long uDecimalDividend, ScaleMetrics divisorMetrics, long uDecimalDivisor) {
268                if (divisorMetrics.isValidIntegerValue(uDecimalDividend)) {
269                        // just do it, multiplication result fits in long
270                        final long scaledDividend = divisorMetrics.multiplyByScaleFactor(uDecimalDividend);
271                        final long quot = scaledDividend / uDecimalDivisor;
272                        final long rem = scaledDividend - quot * uDecimalDivisor;
273                        return quot + Rounding.calculateRoundingIncrementForDivision(rounding, quot, rem, uDecimalDivisor);
274                }
275                if (divisorMetrics.isValidIntegerValue(uDecimalDivisor)) {
276                        // perform component wise division (reminder fits in long after
277                        // scaling)
278                        final long integralPart = uDecimalDividend / uDecimalDivisor;
279                        final long remainder = uDecimalDividend - integralPart * uDecimalDivisor;
280                        final long scaledReminder = divisorMetrics.multiplyByScaleFactor(remainder);
281                        final long fractionalPart = scaledReminder / uDecimalDivisor;
282                        final long subFractionalPart = scaledReminder - fractionalPart * uDecimalDivisor;
283                        final long truncated = divisorMetrics.multiplyByScaleFactor(integralPart) + fractionalPart;
284                        return truncated + Rounding.calculateRoundingIncrementForDivision(rounding, truncated, subFractionalPart, uDecimalDivisor);
285                }
286                return Div.scaleTo128divBy64(divisorMetrics, rounding, uDecimalDividend, uDecimalDivisor);
287        }
288
289        /**
290         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
291         * without rounding and with overflow checks.
292         * 
293         * @param arith
294         *            the arithmetic with scale metrics and overflow mode
295         * @param uDecimalDividend
296         *            the unscaled decimal dividend
297         * @param uDecimalDivisor
298         *            the unscaled decimal divisor
299         * @return the division result without rounding and with overflow checks
300         */
301        public static final long divideChecked(DecimalArithmetic arith, long uDecimalDividend, long uDecimalDivisor) {
302                // special cases first
303                final SpecialDivisionResult special = SpecialDivisionResult.getFor(arith, uDecimalDividend, uDecimalDivisor);
304                if (special != null) {
305                        return special.divide(arith, uDecimalDividend, uDecimalDivisor);
306                }
307                // div by power of 10
308                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
309                final ScaleMetrics pow10 = Scales.findByScaleFactor(Math.abs(uDecimalDivisor));
310                if (pow10 != null) {
311                        return Pow10.divideByPowerOf10Checked(arith, uDecimalDividend, scaleMetrics, uDecimalDivisor > 0, pow10);
312                }
313                return divideChecked(scaleMetrics, uDecimalDividend, scaleMetrics, uDecimalDivisor);
314        }
315
316        /**
317         * Calculates unchecked division by an unscaled value with the given scale
318         * without rounding and with overflow checks.
319         * 
320         * @param arith
321         *            the arithmetic associated with the dividend
322         * @param uDecimalDividend
323         *            the unscaled decimal dividend
324         * @param unscaledDivisor
325         *            the long divisor
326         * @param scale
327         *            the scale of the divisor
328         * @return the division result without rounding and with overflow checks
329         */
330        public static final long divideByUnscaledChecked(DecimalArithmetic arith, long uDecimalDividend, long unscaledDivisor, int scale) {
331                if (scale > Scales.MAX_SCALE) {
332                        throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale);
333                }
334                if (uDecimalDividend == 0 & unscaledDivisor != 0) {
335                        return 0;
336                } else if (scale == 0) {
337                        return Checked.divideByLong(arith, uDecimalDividend, unscaledDivisor);
338                } else if (scale < 0) {
339                        if (Checked.isDivideOverflow(uDecimalDividend, unscaledDivisor)) {
340                                return -Pow10.multiplyByPowerOf10Checked(arith, uDecimalDividend, scale);
341                        }
342                        return Pow10.multiplyByPowerOf10Checked(arith, uDecimalDividend / unscaledDivisor, scale);
343                }
344                final ScaleMetrics divisorMetrics = Scales.getScaleMetrics(scale);
345                return divideChecked(arith.getScaleMetrics(), uDecimalDividend, divisorMetrics, unscaledDivisor);
346        }
347
348        /**
349         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
350         * without rounding and with overflow checks.
351         * 
352         * @param dividendMetrics
353         *            the metrics associated with the dividend
354         * @param uDecimalDividend
355         *            the unscaled decimal dividend
356         * @param divisorMetrics
357         *            the scale metrics associated with the divisor
358         * @param uDecimalDivisor
359         *            the unscaled decimal divisor
360         * @return the division result without rounding and with overflow checks
361         */
362        private static final long divideChecked(ScaleMetrics dividendMetrics, long uDecimalDividend, ScaleMetrics divisorMetrics, long uDecimalDivisor) {
363                try {
364                        // WE WANT: uDecimalDividend * 10^divisorScale / unscaledDivisor
365                        if (divisorMetrics.isValidIntegerValue(uDecimalDividend)) {
366                                // just do it, multiplication result fits in long (division can only overflow for scale=1)
367                                return divisorMetrics.multiplyByScaleFactor(uDecimalDividend) / uDecimalDivisor;
368                        }
369                        // perform component wise division
370                        final long integralPart = Checked.divideLong(uDecimalDividend, uDecimalDivisor);
371                        final long remainder = uDecimalDividend - integralPart * uDecimalDivisor;
372                        final long fractionalPart;
373                        if (divisorMetrics.isValidIntegerValue(remainder)) {
374                                // scaling and result can't overflow because of the above condition
375                                fractionalPart = divisorMetrics.multiplyByScaleFactor(remainder) / uDecimalDivisor;
376                        } else {
377                                // result can't overflow because reminder is smaller than
378                                // divisor, i.e. -1 < result < 1
379                                fractionalPart = scaleTo128divBy64(divisorMetrics, DecimalRounding.DOWN, remainder, uDecimalDivisor);
380                        }
381                        return Checked.addLong(divisorMetrics.multiplyByScaleFactorExact(integralPart), fractionalPart);
382                } catch (ArithmeticException e) {
383                        throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + dividendMetrics.toString(uDecimalDividend) + " / "
384                                        + divisorMetrics.toString(uDecimalDivisor), e);
385                }
386        }
387
388        /**
389         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
390         * with rounding and with overflow checks.
391         * 
392         * @param arith
393         *            the arithmetic with scale metrics and overflow mode
394         * @param rounding
395         *            the decimal rounding to apply if rounding is necessary
396         * @param uDecimalDividend
397         *            the unscaled decimal dividend
398         * @param uDecimalDivisor
399         *            the unscaled decimal divisor
400         * @return the division result with rounding and with overflow checks
401         */
402        public static final long divideChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimalDividend, long uDecimalDivisor) {
403                // special cases first
404                final SpecialDivisionResult special = SpecialDivisionResult.getFor(arith, uDecimalDividend, uDecimalDivisor);
405                if (special != null) {
406                        return special.divide(arith, uDecimalDividend, uDecimalDivisor);
407                }
408                // div by power of 10
409                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
410                final ScaleMetrics pow10 = Scales.findByScaleFactor(Math.abs(uDecimalDivisor));
411                if (pow10 != null) {
412                        return Pow10.divideByPowerOf10Checked(arith, rounding, uDecimalDividend, scaleMetrics, uDecimalDivisor > 0, pow10);
413                }
414                return divideChecked(rounding, scaleMetrics, uDecimalDividend, scaleMetrics, uDecimalDivisor);
415        }
416
417        /**
418         * Calculates unchecked division by an unscaled value with the given scale
419         * without rounding and with overflow checks.
420         * 
421         * @param arith
422         *            the arithmetic associated with the dividend
423         * @param rounding
424         *            the ronuding to apply
425         * @param uDecimalDividend
426         *            the unscaled decimal dividend
427         * @param unscaledDivisor
428         *            the long divisor
429         * @param scale
430         *            the scale of the divisor
431         * @return the division result without rounding and with overflow checks
432         */
433        public static final long divideByUnscaledChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimalDividend, long unscaledDivisor, int scale) {
434                if (scale > Scales.MAX_SCALE) {
435                        throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale);
436                }
437                if (uDecimalDividend == 0 & unscaledDivisor != 0) {
438                        return 0;
439                } else if (scale == 0) {
440                        return divideByLongChecked(arith, rounding, uDecimalDividend, unscaledDivisor);
441                } else if (scale < 0) {
442                        if (Checked.isDivideOverflow(uDecimalDividend, unscaledDivisor)) {
443                                return -Pow10.multiplyByPowerOf10Checked(arith, RoundingInverse.SIGN_REVERSION.invert(rounding), uDecimalDividend, scale);
444                        }
445                        //NOTE: rounding twice could be a problem here, e.g. consider HALF_UP with 10.51 and 10.49
446                        final long quot;
447                        switch (rounding) {
448                        case HALF_UP:
449                                quot = divideByLongChecked(arith, DecimalRounding.DOWN, uDecimalDividend, unscaledDivisor);
450                                break;
451                        case HALF_DOWN:
452                                quot = divideByLongChecked(arith, DecimalRounding.UP, uDecimalDividend, unscaledDivisor);
453                                break;
454                        case HALF_EVEN: {
455                                //try HALF_UP first
456                                final long quotD = divideByLongChecked(arith, DecimalRounding.DOWN, uDecimalDividend, unscaledDivisor);
457                                final long powHU = Pow10.multiplyByPowerOf10Checked(arith, DecimalRounding.HALF_UP, quotD, scale);
458                                if (0 == (powHU & 0x1)) {
459                                        //even, we're done
460                                        return powHU;
461                                }
462                                //odd, HALF_DOWN may be even in which case it should win
463                                final long quotU = divideByLongChecked(arith, DecimalRounding.UP, uDecimalDividend, unscaledDivisor);
464                                final long powHD = Pow10.multiplyByPowerOf10Checked(arith, DecimalRounding.HALF_DOWN, quotU, scale);
465                                return powHD;//either even or the same as powHU
466                        }
467                        default:
468                                quot = divideByLongChecked(arith, rounding, uDecimalDividend, unscaledDivisor);
469                                break;
470                        }
471                        return Pow10.multiplyByPowerOf10Checked(arith, rounding, quot, scale);
472                }
473                final ScaleMetrics divisorMetrics = Scales.getScaleMetrics(scale);
474                return divideChecked(rounding, arith.getScaleMetrics(), uDecimalDividend, divisorMetrics, unscaledDivisor);
475        }
476
477        /**
478         * Calculates {@code (uDecimalDividend * scaleFactor) / uDecimalDivisor}
479         * with rounding and with overflow checks.
480         * 
481         * @param rounding
482         *            the ronuding to apply
483         * @param dividendMetrics
484         *            the matrics associated with the dividend
485         * @param uDecimalDividend
486         *            the unscaled decimal dividend
487         * @param divisorMetrics
488         *            the scale metrics associated with the divisor
489         * @param uDecimalDivisor
490         *            the unscaled decimal divisor
491         * @return the division result with rounding and with overflow checks
492         */
493        private static final long divideChecked(DecimalRounding rounding, ScaleMetrics dividendMetrics, long uDecimalDividend, ScaleMetrics divisorMetrics, long uDecimalDivisor) {
494                try {
495                        // WE WANT: uDecimalDividend * 10^divisorScale / unscaledDivisor
496                        if (divisorMetrics.isValidIntegerValue(uDecimalDividend)) {
497                                // just do it, multiplication result fits in long
498                                final long scaledDividend = divisorMetrics.multiplyByScaleFactor(uDecimalDividend);
499                                final long quot = scaledDividend / uDecimalDivisor;//cannot overflow for scale>1
500                                final long rem = scaledDividend - quot * uDecimalDivisor;
501
502                                //cannot overflow for scale > 1 because of quot
503                                return quot + Rounding.calculateRoundingIncrementForDivision(rounding, quot, rem, uDecimalDivisor);
504                        }
505
506                        // perform component wise division
507                        final long integralPart = Checked.divideLong(uDecimalDividend, uDecimalDivisor);
508                        final long remainder = uDecimalDividend - integralPart * uDecimalDivisor;
509
510                        if (divisorMetrics.isValidIntegerValue(remainder)) {
511                                final long scaledReminder = divisorMetrics.multiplyByScaleFactor(remainder);
512                                final long fractionalPart = scaledReminder / uDecimalDivisor;//cannot overflow for scale>1
513                                final long subFractionalPart = scaledReminder - fractionalPart * uDecimalDivisor;
514
515                                final long result = Checked.addLong(divisorMetrics.multiplyByScaleFactorExact(integralPart), fractionalPart);
516                                final long inc = Rounding.calculateRoundingIncrementForDivision(rounding, result, subFractionalPart, uDecimalDivisor);
517                                return Checked.addLong(result, inc);
518                        } else {
519                                final long fractionalPart = Div.scaleTo128divBy64(divisorMetrics, rounding, remainder, uDecimalDivisor);
520                                return Checked.addLong(divisorMetrics.multiplyByScaleFactorExact(integralPart), fractionalPart);
521                        }
522                } catch (ArithmeticException e) {
523                        Exceptions.rethrowIfRoundingNecessary(e);
524                        throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + dividendMetrics.toString(uDecimalDividend) + " / " + divisorMetrics.toString(uDecimalDivisor), e);
525                }
526        }
527
528        /**
529         * Calculates {@code uDecimalDividend * scaleFactor / uDecimalDivisor} performing the multiplication into a 128 bit product
530         * and then performing a 128 by 64 bit division.
531         * 
532         * @param scaleMetrics          the metrics with scale factor to apply when scaling the dividend
533         * @param rounding                      the rounding to apply if necessary
534         * @param uDecimalDividend      the dividend
535         * @param uDecimalDivisor       the divisor
536         * @return the unscaled decimal result of the division, rounded if necessary and overflow checked if 
537         */
538        private static final long scaleTo128divBy64(ScaleMetrics scaleMetrics, DecimalRounding rounding, long uDecimalDividend, long uDecimalDivisor) {
539                final boolean negative = (uDecimalDividend ^ uDecimalDivisor) < 0;
540                final long absDividend = Math.abs(uDecimalDividend);
541                final long absDivisor = Math.abs(uDecimalDivisor);
542
543                // multiply by scale factor into a 128bit integer
544                // HD + Knuth's Algorithm M from [Knu2] section 4.3.1.
545                final int lFactor = (int) (absDividend & LONG_MASK);
546                final int hFactor = (int) (absDividend >>> 32);
547                final long w1, w2, w3;
548                long k, t;
549
550                t = scaleMetrics.mulloByScaleFactor(lFactor);
551                w3 = t & LONG_MASK;
552                k = t >>> 32;
553
554                t = scaleMetrics.mulloByScaleFactor(hFactor) + k;
555                w2 = t & LONG_MASK;
556                w1 = t >>> 32;
557
558                t = scaleMetrics.mulhiByScaleFactor(lFactor) + w2;
559                k = t >>> 32;
560
561                final long hScaled = scaleMetrics.mulhiByScaleFactor(hFactor) + w1 + k;
562                final long lScaled = (t << 32) + w3;
563
564                // divide 128 bit product by 64 bit divisor
565                final long hQuotient, lQuotient;
566                if (Unsigned.isLess(hScaled, absDivisor)) {
567                        hQuotient = 0;
568                        lQuotient = div128by64(rounding, negative, hScaled, lScaled, absDivisor);
569                } else {
570                        hQuotient = Unsigned.divide(hScaled, absDivisor);
571                        final long rem = hScaled - hQuotient * absDivisor;
572                        lQuotient = div128by64(rounding, negative, rem, lScaled, absDivisor);
573                }
574                return lQuotient;
575        }
576
577        /**
578         * PRECONDITION: Unsigned.isLess(u1, v0)
579         * <p>
580         * Divides a 128 bit divisor by a 64 bit dividend and returns the signed 64
581         * bit result. Rounding is applied if {@code rounding != null}, otherwise
582         * the value is truncated.
583         * <p>
584         * From <a
585         * href="http://www.codeproject.com/Tips/785014/UInt-Division-Modulus"
586         * >www.codeproject.com</a>.
587         * 
588         * @param neg
589         *            true if result is negative
590         * @param u1
591         *            high order 64 bits of dividend
592         * @param u0
593         *            low order 64 bits of dividend
594         * @param v0
595         *            64 bit divisor
596         * @param rounding
597         *            rounding to apply, or null to truncate result
598         * @return the signed quotient, rounded if {@code rounding != null}
599         */
600        static final long div128by64(final DecimalRounding rounding, final boolean neg, final long u1, final long u0, final long v0) {
601                final long q, r;
602
603                final long un1, un0, vn1, vn0, un32, un21, un10;
604                long q1, q0;
605
606                final int s = Long.numberOfLeadingZeros(v0);
607
608                final long v = v0 << s;
609                vn1 = v >>> 32;
610                vn0 = v & LONG_MASK;
611
612                un32 = (u1 << s) | (u0 >>> (64 - s)) & (-s >> 63);
613                un10 = u0 << s;
614
615                un1 = un10 >>> 32;
616                un0 = un10 & LONG_MASK;
617
618                q1 = div128by64part(un32, un1, vn1, vn0);
619                un21 = (un32 << 32) + (un1 - (q1 * v));
620                q0 = div128by64part(un21, un0, vn1, vn0);
621                q = (q1 << 32) | q0;
622
623                // apply sign and rounding
624                if (rounding == DecimalRounding.DOWN) {
625                        return neg ? -q : q;
626                }
627
628                r = ((un21 << 32) + un0 - q0 * v) >>> s;
629                final TruncatedPart truncatedPart = Rounding.truncatedPartFor(Math.abs(r), v0);
630                final int inc = rounding.calculateRoundingIncrement(neg ? -1 : 1, q, truncatedPart);
631                return (neg ? -q : q) + inc;
632        }
633
634        private static final long div128by64part(final long unCB, final long unA, final long vn1, final long vn0) {
635                // quotient and reminder, first guess
636                long q = unsignedDiv64by32(unCB, vn1);
637                long rhat = unCB - q * vn1;
638
639                // correct, first attempt
640                while (q > LONG_MASK) {
641                        q--;
642                        rhat += vn1;
643                        if (rhat > LONG_MASK) {
644                                return q;
645                        }
646                }
647                // correct, second attempt
648                long left = q * vn0;
649                long right = (rhat << 32) | unA;
650                while (Unsigned.isGreater(left, right)) {
651                        q--;
652                        rhat += vn1;
653                        if (rhat > LONG_MASK) {
654                                return q;
655                        }
656                        left -= vn0;
657                        right = (rhat << 32) | unA;
658                }
659                return q;
660        }
661
662        /**
663         * Returns dividend / divisor, where the dividend and divisor are treated as
664         * unsigned 64-bit quantities.
665         * <p>
666         * From Guava's <a href=
667         * "http://docs.guava-libraries.googlecode.com/git/javadoc/src-html/com/google/common/primitives/UnsignedLongs.html"
668         * >UnsignedLongs</a>.
669         *
670         * @param dividend
671         *            the dividend (numerator)
672         * @param divisor
673         *            the divisor (denominator)
674         * @return the unsigned quotient {@code dividend / divisor}
675         * @throws ArithmeticException
676         *             if divisor is 0
677         */
678        private static final long unsignedDiv64by32(long dividend, long divisor) {
679                // Optimization - use signed division if dividend < 2^63
680                if (dividend >= 0) {
681                        return dividend / divisor;
682                }
683                // Optimization if divisor is even
684                if (0 == (divisor & 0x1)) {
685                        return (dividend >>> 1) / (divisor >>> 1);
686                }
687
688                /*
689                 * Otherwise, approximate the quotient, check, and correct if necessary.
690                 * Our approximation is guaranteed to be either exact or one less than
691                 * the correct value. This follows from fact that floor(floor(x)/i) ==
692                 * floor(x/i) for any real x and integer i != 0. The proof is not quite
693                 * trivial.
694                 */
695                final long quotient = ((dividend >>> 1) / divisor) << 1;
696                final long rem = dividend - quotient * divisor;
697                return quotient + (((rem >= divisor) | (rem < 0)) ? 1 : 0);
698        }
699
700        // no instances
701        private Div() {
702                super();
703        }
704
705}