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.base;
025
026import java.math.BigDecimal;
027import java.math.BigInteger;
028import java.math.RoundingMode;
029
030import org.decimal4j.api.Decimal;
031import org.decimal4j.api.DecimalArithmetic;
032import org.decimal4j.api.ImmutableDecimal;
033import org.decimal4j.api.MutableDecimal;
034import org.decimal4j.scale.ScaleMetrics;
035import org.decimal4j.truncate.CheckedRounding;
036import org.decimal4j.truncate.OverflowMode;
037import org.decimal4j.truncate.TruncationPolicy;
038import org.decimal4j.truncate.UncheckedRounding;
039
040/**
041 * Common base class for {@link AbstractImmutableDecimal immutable} and
042 * {@link AbstractMutableDecimal mutable} {@link Decimal} numbers of different
043 * scales.
044 * 
045 * @param <S>
046 *            the scale metrics type associated with this decimal
047 * @param <D>
048 *            the concrete class implementing this decimal
049 */
050@SuppressWarnings("serial")
051abstract public class AbstractDecimal<S extends ScaleMetrics, D extends AbstractDecimal<S, D>> 
052                extends Number implements Decimal<S> {
053
054        /**
055         * Returns this or a new {@code Decimal} whose value is
056         * <tt>(unscaled &times; 10<sup>-scale</sup>)</tt>.
057         * <p>
058         * The returned value is a new instance if this decimal is an
059         * {@link ImmutableDecimal}. If it is a {@link MutableDecimal} then its
060         * internal state is altered and {@code this} is returned as result now
061         * representing <tt>(unscaled &times; 10<sup>-scale</sup>)</tt>.
062         * 
063         * @param unscaled
064         *            unscaled value to be returned as a {@code Decimal}
065         * @return <tt>unscaled &times; 10<sup>-scale</sup></tt>
066         */
067        abstract protected D createOrAssign(long unscaled);
068
069        /**
070         * Returns a new {@code Decimal} whose value is
071         * <tt>(unscaled &times; 10<sup>-scale</sup>)</tt>.
072         * 
073         * @param unscaled
074         *            unscaled value to be returned as a {@code Decimal}
075         * @return <tt>unscaled &times; 10<sup>-scale</sup></tt>
076         */
077        abstract protected D create(long unscaled);
078
079        /**
080         * Returns a new {@code Decimal} array of the specified {@code length}.
081         * 
082         * @param length
083         *            the length of the array to return
084         * @return {@code new D[length]}
085         */
086        abstract protected D[] createArray(int length);
087
088        /**
089         * Returns {@code this} decimal value as concrete implementation subtype.
090         * 
091         * @return {@code this}
092         */
093        abstract protected D self();
094
095        /**
096         * Returns the default arithmetic performing unchecked operations with
097         * rounding mode {@link RoundingMode#HALF_UP HALF_UP}.
098         * 
099         * @return default arithmetic with {@link RoundingMode#HALF_UP HALF_UP}
100         *         rounding and {@link OverflowMode#UNCHECKED UNCHECKED} overflow
101         *         mode
102         */
103        protected DecimalArithmetic getDefaultArithmetic() {
104                return getScaleMetrics().getDefaultArithmetic();
105        }
106
107        /**
108         * Returns the default arithmetic performing checked operations with
109         * rounding mode {@link RoundingMode#HALF_UP HALF_UP}.
110         * 
111         * @return default arithmetic with {@link RoundingMode#HALF_UP HALF_UP}
112         *         rounding and {@link OverflowMode#CHECKED CHECKED} overflow mode
113         */
114        protected DecimalArithmetic getDefaultCheckedArithmetic() {
115                return getScaleMetrics().getDefaultCheckedArithmetic();
116        }
117
118        /**
119         * Returns the default arithmetic performing checked operations with
120         * rounding mode {@link RoundingMode#HALF_UP HALF_UP} and the specified
121         * {@code overflowMode}.
122         * 
123         * @param overflowMode
124         *            the overflow for the returned arithmetic
125         * 
126         * @return default arithmetic with {@link RoundingMode#HALF_UP HALF_UP}
127         *         rounding and the given {@code overflowMode}
128         */
129        protected DecimalArithmetic getArithmeticFor(OverflowMode overflowMode) {
130                return getScaleMetrics().getArithmetic(overflowMode == OverflowMode.CHECKED ? CheckedRounding.HALF_UP : UncheckedRounding.HALF_UP);
131        }
132
133        /**
134         * Returns the arithmetic performing unchecked operations with rounding mode
135         * {@link RoundingMode#DOWN DOWN}.
136         * 
137         * @return arithmetic with {@link RoundingMode#DOWN DOWN} rounding and
138         *         {@link OverflowMode#UNCHECKED UNCHECKED} overflow mode
139         */
140        protected DecimalArithmetic getRoundingDownArithmetic() {
141                return getScaleMetrics().getRoundingDownArithmetic();
142        }
143
144        /**
145         * Returns the arithmetic performing unchecked operations with rounding mode
146         * {@link RoundingMode#FLOOR FLOOR}.
147         * 
148         * @return arithmetic with {@link RoundingMode#FLOOR FLOOR} rounding and
149         *         {@link OverflowMode#UNCHECKED UNCHECKED} overflow mode
150         */
151        protected DecimalArithmetic getRoundingFloorArithmetic() {
152                return getScaleMetrics().getRoundingFloorArithmetic();
153        }
154
155        /**
156         * Returns the arithmetic performing unchecked operations with rounding mode
157         * {@link RoundingMode#HALF_EVEN HALF_EVEN}.
158         * 
159         * @return arithmetic with {@link RoundingMode#HALF_UP HALF_UP} rounding and
160         *         {@link OverflowMode#UNCHECKED UNCHECKED} overflow mode
161         */
162        protected DecimalArithmetic getRoundingHalfEvenArithmetic() {
163                return getScaleMetrics().getRoundingHalfEvenArithmetic();
164        }
165
166        /**
167         * Returns the arithmetic performing unchecked operations with rounding mode
168         * {@link RoundingMode#UNNECESSARY UNNECESSARY}.
169         * 
170         * @return arithmetic with {@link RoundingMode#UNNECESSARY UNNECESSARY}
171         *         rounding and {@link OverflowMode#UNCHECKED UNCHECKED} overflow
172         *         mode
173         */
174        protected DecimalArithmetic getRoundingUnnecessaryArithmetic() {
175                return getScaleMetrics().getRoundingUnnecessaryArithmetic();
176        }
177
178        /**
179         * Returns the arithmetic performing unchecked operations with the specified
180         * {@link RoundingMode}.
181         * 
182         * @param roundingMode
183         *            the rounding for the returned arithmetic
184         * @return arithmetic with specified {@code roundingMode} and
185         *         {@link OverflowMode#UNCHECKED UNCHECKED} overflow mode
186         */
187        protected DecimalArithmetic getArithmeticFor(RoundingMode roundingMode) {
188                return getScaleMetrics().getArithmetic(roundingMode);
189        }
190
191        /**
192         * Returns the arithmetic performing checked operations with the specified
193         * {@link RoundingMode}.
194         * 
195         * @param roundingMode
196         *            the rounding for the returned arithmetic
197         * @return arithmetic with specified {@code roundingMode} and
198         *         {@link OverflowMode#CHECKED CHECKED} overflow mode
199         */
200        protected DecimalArithmetic getCheckedArithmeticFor(RoundingMode roundingMode) {
201                return getScaleMetrics().getCheckedArithmetic(roundingMode);
202        }
203
204        /**
205         * Returns the arithmetic for the specified {@code truncationPolicy}.
206         * 
207         * @param truncationPolicy
208         *            the truncation policy for the returned arithmetic
209         * @return arithmetic performing operations according to the given
210         *         {@code truncationPolicy}
211         */
212        protected DecimalArithmetic getArithmeticFor(TruncationPolicy truncationPolicy) {
213                return getScaleMetrics().getArithmetic(truncationPolicy);
214        }
215
216        /* -------------------- Number and simular conversion ------------------- */
217
218        @Override
219        public byte byteValueExact() {
220                final long num = longValueExact(); // will check decimal part
221                if ((byte) num != num) {
222                        throw new ArithmeticException("Overflow: " + num + " is out of the possible range for a byte");
223                }
224                return (byte) num;
225        }
226
227        @Override
228        public short shortValueExact() {
229                final long num = longValueExact(); // will check decimal part
230                if ((short) num != num) {
231                        throw new ArithmeticException("Overflow: " + num + " is out of the possible range for a short");
232                }
233                return (short) num;
234        }
235
236        @Override
237        public int intValue() {
238                return (int) longValue();
239        }
240
241        @Override
242        public int intValueExact() {
243                final long num = longValueExact(); // will check decimal part
244                if ((int) num != num) {
245                        throw new ArithmeticException("Overflow: " + num + " is out of the possible range for an int");
246                }
247                return (int) num;
248        }
249
250        @Override
251        public long longValue() {
252                return getRoundingDownArithmetic().toLong(unscaledValue());
253        }
254
255        @Override
256        public long longValueExact() {
257                return getRoundingUnnecessaryArithmetic().toLong(unscaledValue());
258        }
259
260        @Override
261        public long longValue(RoundingMode roundingMode) {
262                return getArithmeticFor(roundingMode).toLong(unscaledValue());
263        }
264
265        @Override
266        public float floatValue() {
267                // NOTE: Must be HALF_EVEN rounding mode according to The Java Language
268                // Specification
269                // @see section 5.1.3 narrowing primitive conversion
270                // @see section 4.2.3. Floating-Point Types, Formats, and Values
271                // @see IEEE 754-1985 Standard for Binary Floating-Point Arithmetic
272                return getRoundingHalfEvenArithmetic().toFloat(unscaledValue());
273        }
274
275        @Override
276        public float floatValue(RoundingMode roundingMode) {
277                return getArithmeticFor(roundingMode).toFloat(unscaledValue());
278        }
279
280        @Override
281        public double doubleValue() {
282                // NOTE: Must be HALF_EVEN rounding mode according to The Java Language
283                // Specification
284                // @see section 5.1.3 narrowing primitive conversion
285                // @see section 4.2.3. Floating-Point Types, Formats, and Values
286                // @see IEEE 754-1985 Standard for Binary Floating-Point Arithmetic
287                return getRoundingHalfEvenArithmetic().toDouble(unscaledValue());
288        }
289
290        @Override
291        public double doubleValue(RoundingMode roundingMode) {
292                return getArithmeticFor(roundingMode).toDouble(unscaledValue());
293        }
294
295        @Override
296        public BigInteger toBigInteger() {
297                return BigInteger.valueOf(longValue());
298        }
299
300        @Override
301        public BigInteger toBigIntegerExact() {
302                return BigInteger.valueOf(longValueExact());
303        }
304
305        @Override
306        public BigInteger toBigInteger(RoundingMode roundingMode) {
307                return BigInteger.valueOf(longValue(roundingMode));
308        }
309
310        @Override
311        public BigDecimal toBigDecimal() {
312                return getDefaultArithmetic().toBigDecimal(unscaledValue());
313        }
314
315        @Override
316        public BigDecimal toBigDecimal(int scale, RoundingMode roundingMode) {
317                return getArithmeticFor(roundingMode).toBigDecimal(unscaledValue(), scale);
318        }
319
320        @Override
321        public D integralPart() {
322                final long unscaled = unscaledValue();
323                final long integral = unscaled - getScaleMetrics().moduloByScaleFactor(unscaled);
324                return createOrAssign(integral);
325        }
326
327        @Override
328        public D fractionalPart() {
329                return createOrAssign(getScaleMetrics().moduloByScaleFactor(unscaledValue()));
330        }
331
332        /* ----------------------------- rounding ------------------------------ */
333        @Override
334        public D round(int precision) {
335                if (precision < getScale()) {
336                        return createOrAssign(getDefaultArithmetic().round(unscaledValue(), precision));
337                }
338                return self();
339        }
340
341        @Override
342        public D round(int precision, RoundingMode roundingMode) {
343                if (precision < getScale()) {
344                        return createOrAssign(getArithmeticFor(roundingMode).round(unscaledValue(), precision));
345                }
346                return self();
347        }
348
349        @Override
350        public D round(int precision, TruncationPolicy truncationPolicy) {
351                if (precision < getScale()) {
352                        return createOrAssign(getArithmeticFor(truncationPolicy).round(unscaledValue(), precision));
353                }
354                return self();
355        }
356
357        /* -------------------------------- add -------------------------------- */
358
359        @Override
360        public D add(Decimal<S> augend) {
361                return addUnscaled(augend.unscaledValue());
362        }
363
364        @Override
365        public D add(Decimal<S> augend, OverflowMode overflowMode) {
366                return addUnscaled(augend.unscaledValue(), overflowMode);
367        }
368
369        @Override
370        public D add(Decimal<?> augend, RoundingMode roundingMode) {
371                return addUnscaled(augend.unscaledValue(), augend.getScale(), roundingMode);
372        }
373
374        @Override
375        public D add(Decimal<?> augend, TruncationPolicy truncationPolicy) {
376                return addUnscaled(augend.unscaledValue(), augend.getScale(), truncationPolicy);
377        }
378
379        @Override
380        public D add(long augend) {
381                return createOrAssign(getDefaultArithmetic().addLong(unscaledValue(), augend));
382        }
383
384        @Override
385        public D add(long augend, OverflowMode overflowMode) {
386                return createOrAssign(getArithmeticFor(overflowMode).addLong(unscaledValue(), augend));
387        }
388
389        @Override
390        public D add(double augend) {
391                final DecimalArithmetic arith = getDefaultCheckedArithmetic();
392                return createOrAssign(arith.add(unscaledValue(), arith.fromDouble(augend)));
393        }
394
395        @Override
396        public D add(double augend, RoundingMode roundingMode) {
397                final DecimalArithmetic arith = getCheckedArithmeticFor(roundingMode);
398                return createOrAssign(arith.add(unscaledValue(), arith.fromDouble(augend)));
399        }
400
401        @Override
402        public D addUnscaled(long unscaledAugend) {
403                final DecimalArithmetic arith = getDefaultArithmetic();
404                return createOrAssign(arith.add(unscaledValue(), unscaledAugend));
405        }
406
407        @Override
408        public D addUnscaled(long unscaledAugend, OverflowMode overflowMode) {
409                final DecimalArithmetic arith = getArithmeticFor(overflowMode);
410                return createOrAssign(arith.add(unscaledValue(), unscaledAugend));
411        }
412
413        @Override
414        public D addUnscaled(long unscaledAugend, int scale) {
415                final DecimalArithmetic arith = getDefaultArithmetic();
416                return createOrAssign(arith.addUnscaled(unscaledValue(), unscaledAugend, scale));
417        }
418
419        @Override
420        public D addUnscaled(long unscaledAugend, int scale, RoundingMode roundingMode) {
421                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
422                return createOrAssign(arith.addUnscaled(unscaledValue(), unscaledAugend, scale));
423        }
424
425        @Override
426        public D addUnscaled(long unscaledAugend, int scale, TruncationPolicy truncationPolicy) {
427                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
428                return createOrAssign(arith.addUnscaled(unscaledValue(), unscaledAugend, scale));
429        }
430
431        @Override
432        public D addSquared(Decimal<S> value) {
433                final DecimalArithmetic arith = getDefaultArithmetic();
434                return createOrAssign(arith.add(unscaledValue(), arith.square(value.unscaledValue())));
435        }
436
437        @Override
438        public D addSquared(Decimal<S> value, RoundingMode roundingMode) {
439                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
440                return createOrAssign(arith.add(unscaledValue(), arith.square(value.unscaledValue())));
441        }
442
443        @Override
444        public D addSquared(Decimal<S> value, TruncationPolicy truncationPolicy) {
445                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
446                return createOrAssign(arith.add(unscaledValue(), arith.square(value.unscaledValue())));
447        }
448
449        /* ------------------------------ subtract ------------------------------ */
450
451        @Override
452        public D subtract(Decimal<S> subtrahend) {
453                return subtractUnscaled(subtrahend.unscaledValue());
454        }
455
456        @Override
457        public D subtract(Decimal<S> subtrahend, OverflowMode overflowMode) {
458                return subtractUnscaled(subtrahend.unscaledValue(), overflowMode);
459        }
460
461        @Override
462        public D subtract(Decimal<?> subtrahend, RoundingMode roundingMode) {
463                return subtractUnscaled(subtrahend.unscaledValue(), subtrahend.getScale(), roundingMode);
464        }
465
466        @Override
467        public D subtract(Decimal<?> subtrahend, TruncationPolicy truncationPolicy) {
468                return subtractUnscaled(subtrahend.unscaledValue(), subtrahend.getScale(), truncationPolicy);
469        }
470
471        @Override
472        public D subtract(long subtrahend) {
473                return createOrAssign(getDefaultArithmetic().subtractLong(unscaledValue(), subtrahend));
474        }
475
476        @Override
477        public D subtract(long subtrahend, OverflowMode overflowMode) {
478                return createOrAssign(getArithmeticFor(overflowMode).subtractLong(unscaledValue(), subtrahend));
479        }
480
481        @Override
482        public D subtract(double subtrahend) {
483                final DecimalArithmetic arith = getDefaultCheckedArithmetic();
484                return createOrAssign(arith.subtract(unscaledValue(), arith.fromDouble(subtrahend)));
485        }
486
487        @Override
488        public D subtract(double subtrahend, RoundingMode roundingMode) {
489                final DecimalArithmetic arith = getCheckedArithmeticFor(roundingMode);
490                return createOrAssign(arith.subtract(unscaledValue(), arith.fromDouble(subtrahend)));
491        }
492
493        @Override
494        public D subtractUnscaled(long unscaledSubtrahend) {
495                final DecimalArithmetic arith = getDefaultArithmetic();
496                return createOrAssign(arith.subtract(unscaledValue(), unscaledSubtrahend));
497        }
498
499        @Override
500        public D subtractUnscaled(long unscaledSubtrahend, OverflowMode overflowMode) {
501                final DecimalArithmetic arith = getArithmeticFor(overflowMode);
502                return createOrAssign(arith.subtract(unscaledValue(), unscaledSubtrahend));
503        }
504
505        @Override
506        public D subtractUnscaled(long unscaledSubtrahend, int scale) {
507                final DecimalArithmetic arith = getDefaultArithmetic();
508                return createOrAssign(arith.subtractUnscaled(unscaledValue(), unscaledSubtrahend, scale));
509        }
510
511        @Override
512        public D subtractUnscaled(long unscaledSubtrahend, int scale, RoundingMode roundingMode) {
513                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
514                return createOrAssign(arith.subtractUnscaled(unscaledValue(), unscaledSubtrahend, scale));
515        }
516
517        @Override
518        public D subtractUnscaled(long unscaledSubtrahend, int scale, TruncationPolicy truncationPolicy) {
519                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
520                return createOrAssign(arith.subtractUnscaled(unscaledValue(), unscaledSubtrahend, scale));
521        }
522
523        @Override
524        public D subtractSquared(Decimal<S> value) {
525                final DecimalArithmetic arith = getDefaultArithmetic();
526                return createOrAssign(arith.subtract(unscaledValue(), arith.square(value.unscaledValue())));
527        }
528
529        @Override
530        public D subtractSquared(Decimal<S> value, RoundingMode roundingMode) {
531                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
532                return createOrAssign(arith.subtract(unscaledValue(), arith.square(value.unscaledValue())));
533        }
534
535        @Override
536        public D subtractSquared(Decimal<S> value, TruncationPolicy truncationPolicy) {
537                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
538                return createOrAssign(arith.subtract(unscaledValue(), arith.square(value.unscaledValue())));
539        }
540
541        /* ------------------------------ multiply ------------------------------ */
542
543        @Override
544        public D multiply(Decimal<S> multiplicand) {
545                return multiplyUnscaled(multiplicand.unscaledValue());
546        }
547
548        @Override
549        public D multiply(Decimal<S> multiplicand, RoundingMode roundingMode) {
550                return multiplyUnscaled(multiplicand.unscaledValue(), roundingMode);
551        }
552
553        @Override
554        public D multiply(Decimal<S> multiplicand, TruncationPolicy truncationPolicy) {
555                return multiplyUnscaled(multiplicand.unscaledValue(), truncationPolicy);
556        }
557
558        @Override
559        public D multiplyBy(Decimal<?> multiplicand) {
560                return multiplyUnscaled(multiplicand.unscaledValue(), multiplicand.getScale());
561        }
562
563        @Override
564        public D multiplyBy(Decimal<?> multiplicand, RoundingMode roundingMode) {
565                return multiplyUnscaled(multiplicand.unscaledValue(), multiplicand.getScale(), roundingMode);
566        }
567
568        @Override
569        public D multiplyBy(Decimal<?> multiplicand, TruncationPolicy truncationPolicy) {
570                return multiplyUnscaled(multiplicand.unscaledValue(), multiplicand.getScale(), truncationPolicy);
571        }
572
573        @Override
574        public D multiply(long multiplicand) {
575                final DecimalArithmetic arith = getDefaultArithmetic();
576                return createOrAssign(arith.multiplyByLong(unscaledValue(), multiplicand));
577        }
578
579        @Override
580        public D multiply(long multiplicand, OverflowMode overflowMode) {
581                final DecimalArithmetic arith = getArithmeticFor(overflowMode);
582                return createOrAssign(arith.multiplyByLong(unscaledValue(), multiplicand));
583        }
584
585        @Override
586        public D multiply(double multiplicand) {
587                final DecimalArithmetic arith = getDefaultCheckedArithmetic();
588                return createOrAssign(arith.multiply(unscaledValue(), arith.fromDouble(multiplicand)));
589        }
590
591        @Override
592        public D multiply(double multiplicand, RoundingMode roundingMode) {
593                final DecimalArithmetic arith = getCheckedArithmeticFor(roundingMode);
594                return createOrAssign(arith.multiply(unscaledValue(), arith.fromDouble(multiplicand)));
595        }
596
597        @Override
598        public D multiplyUnscaled(long unscaledMultiplicand) {
599                final DecimalArithmetic arith = getDefaultArithmetic();
600                return createOrAssign(arith.multiply(unscaledValue(), unscaledMultiplicand));
601        }
602
603        @Override
604        public D multiplyUnscaled(long unscaledMultiplicand, RoundingMode roundingMode) {
605                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
606                return createOrAssign(arith.multiply(unscaledValue(), unscaledMultiplicand));
607        }
608
609        @Override
610        public D multiplyUnscaled(long unscaledMultiplicand, TruncationPolicy truncationPolicy) {
611                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
612                return createOrAssign(arith.multiply(unscaledValue(), unscaledMultiplicand));
613        }
614
615        @Override
616        public D multiplyUnscaled(long unscaledMultiplicand, int scale) {
617                final DecimalArithmetic arith = getDefaultArithmetic();
618                return createOrAssign(arith.multiplyByUnscaled(unscaledValue(), unscaledMultiplicand, scale));
619        }
620
621        @Override
622        public D multiplyUnscaled(long unscaledMultiplicand, int scale, RoundingMode roundingMode) {
623                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
624                return createOrAssign(arith.multiplyByUnscaled(unscaledValue(), unscaledMultiplicand, scale));
625        }
626
627        @Override
628        public D multiplyUnscaled(long unscaledMultiplicand, int scale, TruncationPolicy truncationPolicy) {
629                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
630                return createOrAssign(arith.multiplyByUnscaled(unscaledValue(), unscaledMultiplicand, scale));
631        }
632
633        @Override
634        public D multiplyByPowerOfTen(int n) {
635                return createOrAssign(getDefaultArithmetic().multiplyByPowerOf10(unscaledValue(), n));
636        }
637
638        @Override
639        public D multiplyByPowerOfTen(int n, RoundingMode roundingMode) {
640                return createOrAssign(getArithmeticFor(roundingMode).multiplyByPowerOf10(unscaledValue(), n));
641        }
642
643        @Override
644        public D multiplyByPowerOfTen(int n, TruncationPolicy truncationPolicy) {
645                return createOrAssign(getArithmeticFor(truncationPolicy).multiplyByPowerOf10(unscaledValue(), n));
646        }
647
648        /* ------------------------------ divide ------------------------------ */
649
650        @Override
651        public D divide(Decimal<S> divisor) {
652                return divideUnscaled(divisor.unscaledValue());
653        }
654
655        @Override
656        public D divide(Decimal<S> divisor, RoundingMode roundingMode) {
657                return divideUnscaled(divisor.unscaledValue(), roundingMode);
658        }
659
660        @Override
661        public D divide(Decimal<S> divisor, TruncationPolicy truncationPolicy) {
662                return divideUnscaled(divisor.unscaledValue(), truncationPolicy);
663        }
664
665        @Override
666        public D divideBy(Decimal<?> divisor) {
667                return divideUnscaled(divisor.unscaledValue(), divisor.getScale());
668        }
669
670        @Override
671        public D divideBy(Decimal<?> divisor, RoundingMode roundingMode) {
672                return divideUnscaled(divisor.unscaledValue(), divisor.getScale(), roundingMode);
673        }
674
675        @Override
676        public D divideBy(Decimal<?> divisor, TruncationPolicy truncationPolicy) {
677                return divideUnscaled(divisor.unscaledValue(), divisor.getScale(), truncationPolicy);
678        }
679
680        @Override
681        public D divide(long divisor) {
682                final DecimalArithmetic arith = getDefaultArithmetic();
683                return createOrAssign(arith.divideByLong(unscaledValue(), divisor));
684        }
685
686        @Override
687        public D divide(long divisor, RoundingMode roundingMode) {
688                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
689                return createOrAssign(arith.divideByLong(unscaledValue(), divisor));
690        }
691
692        @Override
693        public D divide(long divisor, TruncationPolicy truncationPolicy) {
694                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
695                return createOrAssign(arith.divideByLong(unscaledValue(), divisor));
696        }
697
698        @Override
699        public D divide(double divisor) {
700                final DecimalArithmetic arith = getDefaultCheckedArithmetic();
701                return createOrAssign(arith.divide(unscaledValue(), arith.fromDouble(divisor)));
702        }
703
704        @Override
705        public D divide(double divisor, RoundingMode roundingMode) {
706                final DecimalArithmetic arith = getCheckedArithmeticFor(roundingMode);
707                return createOrAssign(arith.divide(unscaledValue(), arith.fromDouble(divisor)));
708        }
709
710        @Override
711        public D divideUnscaled(long unscaledDivisor) {
712                final DecimalArithmetic arith = getDefaultArithmetic();
713                return createOrAssign(arith.divide(unscaledValue(), unscaledDivisor));
714        }
715
716        @Override
717        public D divideUnscaled(long unscaledDivisor, RoundingMode roundingMode) {
718                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
719                return createOrAssign(arith.divide(unscaledValue(), unscaledDivisor));
720        }
721
722        @Override
723        public D divideUnscaled(long unscaledDivisor, TruncationPolicy truncationPolicy) {
724                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
725                return createOrAssign(arith.divide(unscaledValue(), unscaledDivisor));
726        }
727
728        @Override
729        public D divideUnscaled(long unscaledDivisor, int scale) {
730                final DecimalArithmetic arith = getDefaultArithmetic();
731                return createOrAssign(arith.divideByUnscaled(unscaledValue(), unscaledDivisor, scale));
732        }
733
734        @Override
735        public D divideUnscaled(long unscaledDivisor, int scale, RoundingMode roundingMode) {
736                final DecimalArithmetic arith = getArithmeticFor(roundingMode);
737                return createOrAssign(arith.divideByUnscaled(unscaledValue(), unscaledDivisor, scale));
738        }
739
740        @Override
741        public D divideUnscaled(long unscaledDivisor, int scale, TruncationPolicy truncationPolicy) {
742                final DecimalArithmetic arith = getArithmeticFor(truncationPolicy);
743                return createOrAssign(arith.divideByUnscaled(unscaledValue(), unscaledDivisor, scale));
744        }
745
746        @Override
747        public D divideExact(Decimal<S> divisor) {
748                return divide(divisor, CheckedRounding.UNNECESSARY);
749        }
750
751        @Override
752        public D divideTruncate(Decimal<S> divisor) {
753                return createOrAssign(getRoundingDownArithmetic().divide(unscaledValue(), divisor.unscaledValue()));
754        }
755
756        @Override
757        public D divideByPowerOfTen(int n) {
758                return createOrAssign(getDefaultArithmetic().divideByPowerOf10(unscaledValue(), n));
759        }
760
761        @Override
762        public D divideByPowerOfTen(int n, RoundingMode roundingMode) {
763                return createOrAssign(getArithmeticFor(roundingMode).divideByPowerOf10(unscaledValue(), n));
764        }
765
766        @Override
767        public D divideByPowerOfTen(int n, TruncationPolicy truncationPolicy) {
768                return createOrAssign(getArithmeticFor(truncationPolicy).divideByPowerOf10(unscaledValue(), n));
769        }
770
771        @Override
772        public D divideToIntegralValue(Decimal<S> divisor) {
773                final long longValue = unscaledValue() / divisor.unscaledValue();
774                return createOrAssign(getScaleMetrics().multiplyByScaleFactor(longValue));
775        }
776
777        @Override
778        public D divideToIntegralValue(Decimal<S> divisor, OverflowMode overflowMode) {
779                if (!overflowMode.isChecked()) {
780                        return divideToIntegralValue(divisor);
781                }
782                final long longValue = divideToLongValue(divisor, overflowMode);
783                return createOrAssign(getScaleMetrics().multiplyByScaleFactorExact(longValue));
784        }
785
786        @Override
787        public long divideToLongValue(Decimal<S> divisor) {
788                return unscaledValue() / divisor.unscaledValue();
789        }
790
791        @Override
792        public long divideToLongValue(Decimal<S> divisor, OverflowMode overflowMode) {
793                final DecimalArithmetic arith = getArithmeticFor(overflowMode == OverflowMode.CHECKED ? CheckedRounding.DOWN : UncheckedRounding.DOWN);
794                try {
795                        return arith.divideByLong(unscaledValue(), divisor.unscaledValue());
796                } catch (ArithmeticException e) {
797                        if (divisor.isZero()) {
798                                throw new ArithmeticException("Division by zero: integral(" + this + " / " + divisor + ")");
799                        }
800                        throw new ArithmeticException("Overflow: integral(" + this + " / " + divisor + ")");
801                }
802        }
803
804        @Override
805        public D[] divideAndRemainder(Decimal<S> divisor) {
806                final long uDividend = unscaledValue();
807                final long uDivisor = divisor.unscaledValue();
808                final long lIntegral = uDividend / uDivisor;
809                final long uIntegral = getScaleMetrics().multiplyByScaleFactor(lIntegral);
810                final long uReminder = uDividend - uDivisor * lIntegral;
811                final D[] result = createArray(2);
812                result[0] = create(uIntegral);
813                result[1] = create(uReminder);
814                return result;
815        }
816
817        @Override
818        public D[] divideAndRemainder(Decimal<S> divisor, OverflowMode overflowMode) {
819                if (!overflowMode.isChecked()) {
820                        return divideAndRemainder(divisor);
821                }
822                try {
823                        final DecimalArithmetic arith = getArithmeticFor(CheckedRounding.DOWN);
824                        final long uDividend = unscaledValue();
825                        final long uDivisor = divisor.unscaledValue();
826                        final long lIntegral = arith.divideByLong(uDividend, uDivisor);
827                        final long uIntegral = getScaleMetrics().multiplyByScaleFactorExact(lIntegral);
828                        final long uReminder = uDividend - uDivisor * lIntegral;
829                        final D[] result = createArray(2);
830                        result[0] = create(uIntegral);
831                        result[1] = create(uReminder);
832                        return result;
833                } catch (ArithmeticException e) {
834                        if (divisor.isZero()) {
835                                throw new ArithmeticException("Division by zero: integral(" + this + " / " + divisor + ")");
836                        }
837                        throw new ArithmeticException("Overflow: integral(" + this + " / " + divisor + ")");
838                }
839        }
840
841        @Override
842        public D remainder(Decimal<S> divisor) {
843                return createOrAssign(unscaledValue() % divisor.unscaledValue());
844        }
845
846        /* ------------------------- other arithmetic ------------------------- */
847
848        @Override
849        public int signum() {
850                return Long.signum(unscaledValue());
851        }
852
853        @Override
854        public D negate() {
855                return createOrAssign(getDefaultArithmetic().negate(unscaledValue()));
856        }
857
858        @Override
859        public D negate(OverflowMode overflowMode) {
860                return createOrAssign(getArithmeticFor(overflowMode).negate(unscaledValue()));
861        }
862
863        @Override
864        public D abs() {
865                final long unscaled = unscaledValue();
866                return unscaled >= 0 ? self() : createOrAssign(getDefaultArithmetic().negate(unscaled));
867        }
868
869        @Override
870        public D abs(OverflowMode overflowMode) {
871                final long unscaled = unscaledValue();
872                return unscaled >= 0 ? self() : createOrAssign(getArithmeticFor(overflowMode).negate(unscaled));
873        }
874
875        @Override
876        public D invert() {
877                return createOrAssign(getDefaultArithmetic().invert(unscaledValue()));
878        }
879
880        @Override
881        public D invert(RoundingMode roundingMode) {
882                return createOrAssign(getArithmeticFor(roundingMode).invert(unscaledValue()));
883        }
884
885        @Override
886        public D invert(TruncationPolicy truncationPolicy) {
887                return createOrAssign(getArithmeticFor(truncationPolicy).invert(unscaledValue()));
888        }
889
890        @Override
891        public D square() {
892                return createOrAssign(getDefaultArithmetic().square(unscaledValue()));
893        }
894
895        @Override
896        public D square(RoundingMode roundingMode) {
897                return createOrAssign(getArithmeticFor(roundingMode).square(unscaledValue()));
898        }
899
900        @Override
901        public D square(TruncationPolicy truncationPolicy) {
902                return createOrAssign(getArithmeticFor(truncationPolicy).square(unscaledValue()));
903        }
904
905        @Override
906        public D sqrt() {
907                return createOrAssign(getDefaultArithmetic().sqrt(unscaledValue()));
908        }
909
910        @Override
911        public D sqrt(RoundingMode roundingMode) {
912                return createOrAssign(getArithmeticFor(roundingMode).sqrt(unscaledValue()));
913        }
914
915        @Override
916        public D shiftLeft(int n) {
917                // NOTE: FLOOR is default for shift!
918                return createOrAssign(getRoundingFloorArithmetic().shiftLeft(unscaledValue(), n));
919        }
920
921        @Override
922        public D shiftLeft(int n, RoundingMode roundingMode) {
923                return createOrAssign(getArithmeticFor(roundingMode).shiftLeft(unscaledValue(), n));
924        }
925
926        @Override
927        public D shiftLeft(int n, TruncationPolicy truncationPolicy) {
928                return createOrAssign(getArithmeticFor(truncationPolicy).shiftLeft(unscaledValue(), n));
929        }
930
931        @Override
932        public D shiftRight(int n) {
933                // NOTE: FLOOR is default for shift!
934                return createOrAssign(getRoundingFloorArithmetic().shiftRight(unscaledValue(), n));
935        }
936
937        @Override
938        public D shiftRight(int n, RoundingMode roundingMode) {
939                return createOrAssign(getArithmeticFor(roundingMode).shiftRight(unscaledValue(), n));
940        }
941
942        @Override
943        public D shiftRight(int n, TruncationPolicy truncationPolicy) {
944                return createOrAssign(getArithmeticFor(truncationPolicy).shiftRight(unscaledValue(), n));
945        }
946
947        @Override
948        public D pow(int n) {
949                return createOrAssign(getDefaultArithmetic().pow(unscaledValue(), n));
950        }
951
952        @Override
953        public D pow(int n, RoundingMode roundingMode) {
954                return createOrAssign(getArithmeticFor(roundingMode).pow(unscaledValue(), n));
955        }
956
957        @Override
958        public D pow(int n, TruncationPolicy truncationPolicy) {
959                return createOrAssign(getArithmeticFor(truncationPolicy).pow(unscaledValue(), n));
960        }
961
962        /* --------------------------- compare etc. ---------------------------- */
963
964        @Override
965        public int compareTo(Decimal<S> other) {
966                return getDefaultArithmetic().compare(unscaledValue(), other.unscaledValue());
967        }
968
969        @Override
970        public boolean isEqualTo(Decimal<S> other) {
971                return compareTo(other) == 0;
972        }
973
974        @Override
975        public boolean isGreaterThan(Decimal<S> other) {
976                return compareTo(other) > 0;
977        }
978
979        @Override
980        public boolean isGreaterThanOrEqualTo(Decimal<S> other) {
981                return compareTo(other) >= 0;
982        }
983
984        @Override
985        public boolean isLessThan(Decimal<S> other) {
986                return compareTo(other) < 0;
987        }
988
989        @Override
990        public boolean isLessThanOrEqualTo(Decimal<S> other) {
991                return compareTo(other) <= 0;
992        }
993
994        @Override
995        public boolean isZero() {
996                return unscaledValue() == 0;
997        }
998
999        @Override
1000        public boolean isOne() {
1001                return unscaledValue() == getScaleMetrics().getScaleFactor();
1002        }
1003
1004        @Override
1005        public boolean isUlp() {
1006                return unscaledValue() == 1;
1007        }
1008
1009        @Override
1010        public boolean isMinusOne() {
1011                return unscaledValue() == -getScaleMetrics().getScaleFactor();
1012        }
1013
1014        @Override
1015        public boolean isPositive() {
1016                return unscaledValue() > 0;
1017        }
1018
1019        @Override
1020        public boolean isNonNegative() {
1021                return unscaledValue() >= 0;
1022        }
1023
1024        @Override
1025        public boolean isNegative() {
1026                return unscaledValue() < 0;
1027        }
1028
1029        @Override
1030        public boolean isNonPositive() {
1031                return unscaledValue() <= 0;
1032        }
1033
1034        @Override
1035        public boolean isIntegral() {
1036                return getScaleMetrics().moduloByScaleFactor(unscaledValue()) == 0;
1037        }
1038
1039        @Override
1040        public boolean isIntegralPartZero() {
1041                final long unscaled = unscaledValue();
1042                final long one = getScaleMetrics().getScaleFactor();
1043                return one > unscaled & unscaled > -one;
1044        }
1045
1046        @Override
1047        public boolean isBetweenZeroAndOne() {
1048                final long unscaled = unscaledValue();
1049                return 0 <= unscaled && unscaled < getScaleMetrics().getScaleFactor();
1050        }
1051
1052        @Override
1053        public boolean isBetweenZeroAndMinusOne() {
1054                final long unscaled = unscaledValue();
1055                return 0 >= unscaled && unscaled > -(getScaleMetrics().getScaleFactor());
1056        }
1057
1058        @Override
1059        public int compareToNumerically(Decimal<?> other) {
1060                return getDefaultArithmetic().compareToUnscaled(unscaledValue(), other.unscaledValue(), other.getScale());
1061        }
1062
1063        @Override
1064        public boolean isEqualToNumerically(Decimal<?> other) {
1065                return compareToNumerically(other) == 0;
1066        }
1067
1068        @Override
1069        public Decimal<S> min(Decimal<S> val) {
1070                return isLessThanOrEqualTo(val) ? this : val;
1071        }
1072
1073        @Override
1074        public Decimal<S> max(Decimal<S> val) {
1075                return isGreaterThanOrEqualTo(val) ? this : val;
1076        }
1077
1078        /**
1079         * Returns the minimum of this {@code Decimal} and {@code val}.
1080         *
1081         * @param val
1082         *            value with which the minimum is to be computed.
1083         * @return the {@code Decimal} whose value is the lesser of this
1084         *         {@code Decimal} and {@code val}. If they are equal, as defined by
1085         *         the {@link #compareTo(Decimal) compareTo} method, {@code this} is
1086         *         returned.
1087         * @see #compareTo(Decimal)
1088         */
1089        public D min(D val) {
1090                return isLessThanOrEqualTo(val) ? self() : val;
1091        }
1092
1093        /**
1094         * Returns the maximum of this {@code Decimal} and {@code val}.
1095         *
1096         * @param val
1097         *            value with which the maximum is to be computed.
1098         * @return the {@code Decimal} whose value is the greater of this
1099         *         {@code Decimal} and {@code val}. If they are equal, as defined by
1100         *         the {@link #compareTo(Decimal) compareTo} method, {@code this} is
1101         *         returned.
1102         * @see #compareTo(Decimal)
1103         */
1104        public D max(D val) {
1105                return isGreaterThanOrEqualTo(val) ? self() : val;
1106        }
1107
1108        @Override
1109        public D avg(Decimal<S> val) {
1110                return createOrAssign(getDefaultArithmetic().avg(unscaledValue(), val.unscaledValue()));
1111        }
1112
1113        @Override
1114        public D avg(Decimal<S> val, RoundingMode roundingMode) {
1115                return createOrAssign(getArithmeticFor(roundingMode).avg(unscaledValue(), val.unscaledValue()));
1116        }
1117
1118        /* ---------------------------- equals etc. ---------------------------- */
1119
1120        @Override
1121        public int hashCode() {
1122                final long unscaled = unscaledValue();
1123                long hash = getScale();
1124                hash = 31 * hash + (unscaled >>> 32);
1125                hash = 31 * hash + unscaled;
1126                return (int) hash;
1127        }
1128
1129        @Override
1130        public boolean equals(Object obj) {
1131                if (obj instanceof Decimal) {
1132                        final Decimal<?> other = (Decimal<?>) obj;
1133                        return unscaledValue() == other.unscaledValue() && getScale() == other.getScale();
1134                }
1135                return false;
1136        }
1137
1138        @Override
1139        public String toString() {
1140                return getDefaultArithmetic().toString(unscaledValue());
1141        }
1142}