1 /*
2 * Oceanus: Java Utilities
3 * Copyright 2012-2026. Tony Washer
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17 package io.github.tonywasher.joceanus.oceanus.decimal;
18
19 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
20
21 import java.math.BigDecimal;
22 import java.math.BigInteger;
23 import java.math.RoundingMode;
24 import java.util.Arrays;
25 import java.util.Objects;
26
27 /**
28 * Provides classes to represent decimal numbers with fixed numbers of decimal digits
29 * {@link #theScale} as Long integers. The decimal value is multiplied by 10 to the power of the
30 * number of decimals for the number ({@link #theFactor}). The integral part of the number can be
31 * expressed as (Value / Factor) and the fractional part as (Value % Factor). Arithmetic is then
32 * performed as whole number arithmetic on these values, with due care taken on multiplication and
33 * division to express the result to the correct number of decimals without losing any part of the
34 * answer to overflow.
35 */
36 public class OceanusDecimal
37 implements Comparable<OceanusDecimal> {
38 /**
39 * Decimal Byte length.
40 */
41 public static final int BYTE_LEN = Long.BYTES + 1;
42
43 /**
44 * The Decimal radix.
45 */
46 public static final int RADIX_TEN = 10;
47
48 /**
49 * The Maximum # of Decimals.
50 */
51 public static final int MAX_DECIMALS = 10;
52
53 /**
54 * Powers of Ten.
55 */
56 private static final long[] POWERS_OF_TEN = getPowersOfTen(MAX_DECIMALS);
57
58 /**
59 * The Shift factor to move top part of long to an integer.
60 */
61 private static final int INT_SHIFT = 32;
62
63 /**
64 * Out of range error text.
65 */
66 private static final String ERROR_RANGE = "Value out of range";
67
68 /**
69 * The unscaled value.
70 */
71 private long theValue;
72
73 /**
74 * The scale.
75 */
76 private int theScale;
77
78 /**
79 * The Decimal factor, used for isolating integral and fractional parts.
80 */
81 private long theFactor;
82
83 /**
84 * Standard constructor.
85 */
86 protected OceanusDecimal() {
87 theValue = 0;
88 theScale = 0;
89 theFactor = 1;
90 }
91
92 /**
93 * Constructor.
94 *
95 * @param pSource the decimal as a string
96 * @throws IllegalArgumentException on invalidly formatted argument
97 */
98 public OceanusDecimal(final String pSource) {
99 /* Parse the string */
100 OceanusDecimalParser.parseDecimalValue(pSource, this);
101
102 /* Remove redundant decimals */
103 reduceScale(0);
104 }
105
106 /**
107 * Constructor.
108 *
109 * @param pSource the decimal as a double
110 */
111 public OceanusDecimal(final double pSource) {
112 /* Convert to string and parse */
113 this(Double.toString(pSource));
114 }
115
116 /**
117 * Constructor.
118 *
119 * @param pSource the source decimal
120 */
121 public OceanusDecimal(final OceanusDecimal pSource) {
122 /* Copy value and scale */
123 setValue(pSource.unscaledValue(), pSource.scale());
124 }
125
126 /**
127 * Constructor.
128 *
129 * @param pUnscaledValue the unscaled value
130 * @param pScale the scale
131 */
132 public OceanusDecimal(final long pUnscaledValue,
133 final int pScale) {
134 /* Store value and scale */
135 setValue(pUnscaledValue, pScale);
136 }
137
138 /**
139 * Create the decimal from a byte array.
140 *
141 * @param pBuffer the buffer
142 */
143 public OceanusDecimal(final byte[] pBuffer) {
144 if (pBuffer == null || pBuffer.length < Long.BYTES + 1) {
145 throw new IllegalArgumentException();
146 }
147 final byte[] myValue = Arrays.copyOf(pBuffer, Long.BYTES);
148 final long myUnscaled = OceanusDataConverter.byteArrayToLong(myValue);
149 final int myScale = pBuffer[Long.BYTES];
150 setValue(myUnscaled, myScale);
151 }
152
153 /**
154 * Obtain the unscaled value of the decimal.
155 *
156 * @return the unscaled value
157 */
158 public long unscaledValue() {
159 return theValue;
160 }
161
162 /**
163 * Obtain the scale of the decimal.
164 *
165 * @return the scale
166 */
167 public int scale() {
168 return theScale;
169 }
170
171 /**
172 * Set the value and scale.
173 *
174 * @param pUnscaledValue the unscaled value
175 * @param pScale the scale
176 */
177 protected final void setValue(final long pUnscaledValue,
178 final int pScale) {
179 /* Validate the scale */
180 recordScale(pScale);
181
182 /* Store value and scale */
183 theValue = pUnscaledValue;
184 }
185
186 /**
187 * Record the scale. The unscaled value is unchanged.
188 *
189 * @param pScale the scale
190 */
191 protected final void recordScale(final int pScale) {
192 /* Validate the scale */
193 validateScale(pScale);
194
195 /* Store scale */
196 theScale = pScale;
197
198 /* Calculate decimal factor */
199 theFactor = getFactor(theScale);
200 }
201
202 /**
203 * Adjust to scale.
204 *
205 * @param pScale required scale
206 */
207 protected void adjustToScale(final int pScale) {
208 /* If the scale is not correct */
209 if (theScale != pScale) {
210 /* Adjust the value appropriately */
211 movePointLeft(pScale
212 - theScale);
213 }
214 }
215
216 /**
217 * Obtain factor.
218 *
219 * @param pDecimals the number of decimals
220 * @return the decimal part of the number
221 */
222 protected static long getFactor(final int pDecimals) {
223 return POWERS_OF_TEN[pDecimals];
224 }
225
226 /**
227 * Validate the scale.
228 *
229 * @param pScale the scale
230 */
231 private static void validateScale(final int pScale) {
232 /* Throw exception on invalid decimals */
233 if (pScale < 0
234 || pScale > MAX_DECIMALS) {
235 throw new IllegalArgumentException("Decimals must be in the range 0 to "
236 + MAX_DECIMALS);
237 }
238 }
239
240 /**
241 * Obtain integral part of number.
242 *
243 * @return the integer part of the number
244 */
245 private long getIntegral() {
246 return theValue
247 / theFactor;
248 }
249
250 /**
251 * Obtain fractional part of number.
252 *
253 * @return the decimal part of the number
254 */
255 private long getFractional() {
256 return theValue
257 % theFactor;
258 }
259
260 /**
261 * Determine whether we have a non-zero value.
262 *
263 * @return <code>true</code> if the value is non-zero, <code>false</code> otherwise.
264 */
265 public boolean isNonZero() {
266 return theValue != 0;
267 }
268
269 /**
270 * Determine whether we have a zero value.
271 *
272 * @return <code>true</code> if the value is zero, <code>false</code> otherwise.
273 */
274 public boolean isZero() {
275 return theValue == 0;
276 }
277
278 /**
279 * Determine whether we have a positive (or zero) value.
280 *
281 * @return <code>true</code> if the value is non-negative, <code>false</code> otherwise.
282 */
283 public boolean isPositive() {
284 return theValue >= 0;
285 }
286
287 /**
288 * Negate the value.
289 */
290 public void negate() {
291 theValue = -theValue;
292 }
293
294 /**
295 * Set to zero value.
296 */
297 public void setZero() {
298 theValue = 0;
299 }
300
301 /**
302 * Returns the sign function.
303 *
304 * @return -1, 0, or 1 as the value of this Decimal is negative, zero, or positive.
305 */
306 public int signum() {
307 if (theValue == 0) {
308 return 0;
309 }
310 return theValue < 0
311 ? -1
312 : 1;
313 }
314
315 /**
316 * Reduce scale. Remove redundant zero digits in scale.
317 *
318 * @param pDesiredScale the desired scale.
319 */
320 protected final void reduceScale(final int pDesiredScale) {
321 /* While we have a large scale */
322 while (theScale > pDesiredScale) {
323 /* If we have relevant digits, break loop */
324 if ((theValue % RADIX_TEN) != 0) {
325 break;
326 }
327
328 /* Adjust the value appropriately */
329 movePointRight(1);
330 }
331 }
332
333 /**
334 * Adjust a value to a different number of decimals.
335 * <p>
336 * If the adjustment is to reduce the number of decimals, the most significant digit of the
337 * discarded digits is examined to determine whether to round up. If the number of decimals is
338 * to be increased, zeros are simply added to the end.
339 *
340 * @param pValue the value to adjust
341 * @param iAdjust the adjustment (positive if # of decimals are to increase, negative if they
342 * are to decrease)
343 * @return the adjusted value
344 */
345 protected static long adjustDecimals(final long pValue,
346 final int iAdjust) {
347 /* Take a copy of the value */
348 long myValue = pValue;
349
350 /* If we need to reduce decimals */
351 if (iAdjust < 0) {
352 /* If we have more than one decimal to remove */
353 if (iAdjust + 1 < 0) {
354 /* Calculate division factor (minus one) */
355 final long myFactor = getFactor(-(iAdjust + 1));
356
357 /* Reduce to 10 times required value */
358 myValue /= myFactor;
359 }
360
361 /* Access last digit */
362 long myDigit = myValue
363 % RADIX_TEN;
364
365 /* Handle negatiove values */
366 int myAdjust = 1;
367 if (myDigit < 0) {
368 myAdjust = -1;
369 myDigit = -myDigit;
370 }
371
372 /* Reduce final decimal and round up if required */
373 myValue /= RADIX_TEN;
374 if (myDigit >= (RADIX_TEN >> 1)) {
375 myValue += myAdjust;
376 }
377
378 /* else if we need to expand fractional product */
379 } else if (iAdjust > 0) {
380 myValue *= getFactor(iAdjust);
381 }
382
383 /* Return the adjusted value */
384 return myValue;
385 }
386
387 /**
388 * Multiply two decimals together to produce a third.
389 * <p>
390 * This function splits each part of the multiplication into integral and fractional parts (a,b)
391 * and (c,d). It then treats each factor as the sum of the two parts (a+b) etc. and calculates
392 * the product as (a.c + a.d + b.c + b.d). To avoid losing significant digits at either end of
393 * the calculation each partial product is split into integral and fractional parts. The
394 * integers are summed together and the fractional parts are summed together at combined decimal
395 * places of the two factors. Once all partial products have been calculated, the integral and
396 * fractional totals are adjusted to the correct number of decimal places and combined. This
397 * allows the multiplication to be built without risk of unnecessary arithmetic overflow.
398 *
399 * @param pFirst the first factor
400 * @param pSecond the second factor
401 */
402 protected void calculateProduct(final OceanusDecimal pFirst,
403 final OceanusDecimal pSecond) {
404 /* Access information about first factor */
405 final long myIntFirst = pFirst.getIntegral();
406 final long myFracFirst = pFirst.getFractional();
407 final int myScaleFirst = pFirst.scale();
408
409 /* Access information about second factor */
410 final long myIntSecond = pSecond.getIntegral();
411 final long myFracSecond = pSecond.getFractional();
412 final int myScaleSecond = pSecond.scale();
413
414 /*
415 * Calculate (a.c) the integral part of the answer and initialise the fractional part (at
416 * maxScale)
417 */
418 int maxScale = myScaleFirst
419 + myScaleSecond;
420 long myIntegral = myIntFirst
421 * myIntSecond;
422 long myFractional = 0;
423
424 /* Calculate (a.d) (@myScaleSecond scale) and split off fractions */
425 long myIntermediate = myIntFirst
426 * myFracSecond;
427 long myFractions = myIntermediate
428 % getFactor(myScaleSecond);
429 myIntermediate -= myFractions;
430 myIntegral += adjustDecimals(myIntermediate, -myScaleSecond);
431 myFractional += adjustDecimals(myFractions, maxScale
432 - myScaleSecond);
433
434 /* Calculate (b.c) (@myScaleFirst scale) and split off fractions */
435 myIntermediate = myIntSecond
436 * myFracFirst;
437 myFractions = myIntermediate
438 % getFactor(myScaleFirst);
439 myIntermediate -= myFractions;
440 myIntegral += adjustDecimals(myIntermediate, -myScaleFirst);
441 myFractional += adjustDecimals(myFractions, maxScale
442 - myScaleFirst);
443
444 /* Calculate (b.d) (@maxScale scale) */
445 myIntermediate = myFracFirst
446 * myFracSecond;
447 myFractional += myIntermediate;
448
449 /* If the maxScale is too large, reduce it */
450 if (maxScale > MAX_DECIMALS) {
451 /* Adjust the decimals */
452 myFractional = adjustDecimals(myFractional, MAX_DECIMALS
453 - maxScale);
454
455 /* Reduce maxScale */
456 maxScale = MAX_DECIMALS;
457 }
458
459 /* Adjust and combine the two calculations */
460 myIntegral = adjustDecimals(myIntegral, theScale);
461 myFractional = adjustDecimals(myFractional, theScale
462 - maxScale);
463 theValue = myIntegral
464 + myFractional;
465 }
466
467 /**
468 * Divide a decimal by another decimal to produce a third.
469 * <p>
470 * The calculation can be written as
471 * <code>x.10<sup>a</sup>/y.10<sup>b</sup> = (x/y).10<sup>a-b</sup> = z.10<sup>c</sup></code>.
472 * <p>
473 * where x is the unscaled dividend, y the unscaled divisor and z the unscaled result, and a,b,c
474 * the relevant scales.
475 * <p>
476 * In order to avoid losing significant digits at either end of the calculation we calculate
477 * (x/y) in integer arithmetic.
478 * <p>
479 * <code>x/y = m, x%y = n => x=my + n</code> where m and n are integers, and
480 * <p>
481 * <code>(x/y).10<sup>a-b</sup> = (my +n).10<sup>a-b</sup>/y = (m + (n/y)).10<sup>a-b</sup></code>
482 * <p>
483 * To obtain the result in the correct scale we find
484 * <p>
485 * <code>z.10<sup>c</sup> = m.10<sup>c-(a-b)</sup> + IntegralPart(n.10<sup>c-(a-b)</sup>/y)</code>
486 * <p>
487 * taking care to round the IntegralPart calculation correctly.
488 * <p>
489 * In the case where it is not possible to avoid overflow, the slower safeQuotient method is used.
490 *
491 * @param pDividend the number to divide
492 * @param pDivisor the number to divide
493 */
494 protected void calculateQuotient(final OceanusDecimal pDividend,
495 final OceanusDecimal pDivisor) {
496 /* Access the two values */
497 final long myDividend = pDividend.unscaledValue();
498 final long myDivisor = pDivisor.unscaledValue();
499
500 /* Check for possible overflow */
501 final int numDivisorBits = 1 + Long.SIZE - Long.numberOfLeadingZeros(pDivisor.isPositive() ? myDivisor : -myDivisor);
502 final int numScaleBits = 1 + Long.SIZE - Long.numberOfLeadingZeros(POWERS_OF_TEN[theScale + 1]);
503 if (numDivisorBits + numScaleBits >= Long.SIZE) {
504 calculateSafeQuotient(pDividend, pDivisor);
505 return;
506 }
507
508 /* Calculate fractions (m,n) */
509 long myInteger = myDividend
510 / myDivisor;
511 long myRemainder = myDividend
512 % myDivisor;
513
514 /* Calculate the required shift (c-(a-b)) */
515 int myShift = scale();
516 myShift += pDivisor.scale()
517 - pDividend.scale();
518
519 /* If the shift is positive */
520 if (myShift > 0) {
521 /* Adjust integer and remainder taking care of rounding for remainder */
522 myInteger = adjustDecimals(myInteger, myShift);
523 myRemainder = adjustDecimals(myRemainder, myShift + 1);
524 myRemainder /= myDivisor;
525 myRemainder = adjustDecimals(myRemainder, -1);
526
527 /* Combine values */
528 theValue = myInteger
529 + myRemainder;
530 } else if (myShift == 0) {
531 /* Only need to adjust remainder for rounding */
532 myRemainder = adjustDecimals(myRemainder, 1);
533 myRemainder /= myDivisor;
534 myRemainder = adjustDecimals(myRemainder, -1);
535
536 /* Combine values */
537 theValue = myInteger
538 + myRemainder;
539 } else {
540 /* Integer value also rounds so add in prior to rounding */
541 myInteger = adjustDecimals(myInteger, myShift + 1);
542 myRemainder = adjustDecimals(myRemainder, myShift + 1);
543 myRemainder /= myDivisor;
544 myInteger += myRemainder;
545 myInteger = adjustDecimals(myInteger, -1);
546
547 /* Combine values */
548 theValue = adjustDecimals(myInteger, -1);
549 }
550 }
551
552 /**
553 * Divide a decimal by another decimal to produce a third using slow BigDecimal arithmetic.
554 * <p>
555 * This is necessary when the quotient is large since there is a danger of overflow in the standard method
556 *
557 * @param pDividend the number to divide
558 * @param pDivisor the number to divide
559 */
560 protected void calculateSafeQuotient(final OceanusDecimal pDividend,
561 final OceanusDecimal pDivisor) {
562 final BigDecimal myDividend = pDividend.toBigDecimal();
563 final BigDecimal myDivisor = pDivisor.toBigDecimal();
564 BigDecimal myResult = myDividend.divide(myDivisor, theScale, RoundingMode.HALF_UP);
565 myResult = myResult.movePointRight(theScale);
566 theValue = myResult.longValue();
567 }
568
569 /**
570 * Add a Decimal to the value. The value of this Decimal is updated and the scale is
571 * maintained.
572 *
573 * @param pValue The Decimal to add to this one.
574 */
575 public void addValue(final OceanusDecimal pValue) {
576 /* Access the parameter at the correct scale */
577 long myDelta = pValue.unscaledValue();
578 final int myScale = pValue.scale();
579 if (theScale != myScale) {
580 myDelta = adjustDecimals(myDelta, theScale
581 - myScale);
582 }
583
584 /* Adjust the value accordingly */
585 theValue += myDelta;
586 }
587
588 /**
589 * Subtract a Decimal from the value. The value of this Decimal is updated and the scale is
590 * maintained.
591 *
592 * @param pValue The decimal to subtract from this one.
593 */
594 public void subtractValue(final OceanusDecimal pValue) {
595 /* Access the parameter at the correct scale */
596 long myDelta = pValue.unscaledValue();
597 final int myScale = pValue.scale();
598 if (theScale != myScale) {
599 myDelta = adjustDecimals(myDelta, theScale
600 - myScale);
601 }
602
603 /* Adjust the value accordingly */
604 theValue -= myDelta;
605 }
606
607 /**
608 * Move decimal point to the left.
609 *
610 * @param pPlaces number of places to move the decimal point
611 */
612 public final void movePointLeft(final int pPlaces) {
613 /* Calculate the new scale */
614 final int myNewScale = theScale
615 + pPlaces;
616
617 /* record the scale */
618 recordScale(myNewScale);
619
620 /* Adjust the value and record the new scale */
621 theValue = adjustDecimals(theValue, pPlaces);
622 }
623
624 /**
625 * Move decimal point to the right.
626 *
627 * @param pPlaces number of places to move the decimal point
628 */
629 public final void movePointRight(final int pPlaces) {
630 /* Call movePointLeft */
631 movePointLeft(-pPlaces);
632 }
633
634 @Override
635 public String toString() {
636 /* Format the value */
637 return OceanusDecimalFormatter.toString(this);
638 }
639
640 /**
641 * Returns the maximum of this Decimal and pValue.
642 *
643 * @param pValue the value to compare.
644 * @return the Decimal whose value is the greater of this Decimal and pValue. If they are
645 * equal, as defined by the compareTo method, this is returned
646 */
647 public OceanusDecimal max(final OceanusDecimal pValue) {
648 /* return the BigDecimal value */
649 return (compareTo(pValue) < 0)
650 ? pValue
651 : this;
652 }
653
654 /**
655 * Returns the minimum of this Decimal and pValue.
656 *
657 * @param pValue the value to compare.
658 * @return the Decimal whose value is the lesser of this Decimal and pValue. If they are
659 * equal, as defined by the compareTo method, this is returned
660 */
661 public OceanusDecimal min(final OceanusDecimal pValue) {
662 /* return the BigDecimal value */
663 return (compareTo(pValue) > 0)
664 ? pValue
665 : this;
666 }
667
668 /**
669 * Returns a new Decimal which is the sum of this Decimal and pValue, and whose scale is the
670 * maximum of the two.
671 *
672 * @param pValue the value to add.
673 * @return the resulting Decimal
674 * @see BigDecimal#add(BigDecimal)
675 */
676 public OceanusDecimal add(final OceanusDecimal pValue) {
677 /* Create the new decimal */
678 final OceanusDecimal myResult;
679
680 /* If the operand has the higher scale */
681 if (theScale < pValue.scale()) {
682 /* Initialise from operand and add this value */
683 myResult = new OceanusDecimal(pValue);
684 myResult.addValue(this);
685 } else {
686 /* Initialise from operand and add this value */
687 myResult = new OceanusDecimal(this);
688 myResult.addValue(pValue);
689 }
690
691 /* return the result */
692 return myResult;
693 }
694
695 /**
696 * Returns a new Decimal which is the difference of this Decimal and pValue, and whose scale
697 * is the maximum of the two.
698 *
699 * @param pValue the value to subtract.
700 * @return the resulting Decimal
701 * @see BigDecimal#subtract
702 */
703 public OceanusDecimal subtract(final OceanusDecimal pValue) {
704 /* Create the new decimal */
705 final OceanusDecimal myResult;
706
707 /* If the operand has the higher scale */
708 if (theScale < pValue.scale()) {
709 /* Initialise from operand and subtract this value */
710 myResult = new OceanusDecimal(pValue);
711 myResult.subtractValue(this);
712 } else {
713 /* Initialise from operand and subtract this value */
714 myResult = new OceanusDecimal(this);
715 myResult.subtractValue(pValue);
716 }
717
718 /* return the result */
719 return myResult;
720 }
721
722 /**
723 * Returns a new Decimal which is the product of this Decimal and pValue, and whose scale is
724 * the sum of the two.
725 *
726 * @param pValue the value to multiply by.
727 * @return the resulting Decimal
728 * @see BigDecimal#multiply(BigDecimal)
729 */
730 public OceanusDecimal multiply(final OceanusDecimal pValue) {
731 /* Create the new decimal at the correct scale */
732 final OceanusDecimal myResult = new OceanusDecimal();
733 myResult.setValue(0, theScale
734 + pValue.scale());
735
736 /* Calculate the product */
737 myResult.calculateProduct(this, pValue);
738
739 /* return the result */
740 return myResult;
741 }
742
743 /**
744 * Multiplies the value by the amount given. The scale remains the same.
745 *
746 * @param pValue the value to multiply by.
747 */
748 public void multiply(final long pValue) {
749 /* Multiply the value */
750 theValue *= pValue;
751 }
752
753 /**
754 * Returns a new Decimal whose value is (this / pValue), and whose scale is the same as this
755 * Decimal.
756 *
757 * @param pValue the value to divide by.
758 * @return the resulting Decimal
759 * @see BigDecimal#divide(BigDecimal)
760 */
761 public OceanusDecimal divide(final OceanusDecimal pValue) {
762 /* Create the new decimal at the correct scale */
763 final OceanusDecimal myResult = new OceanusDecimal();
764 myResult.setValue(0, theScale);
765
766 /* Calculate the quotient */
767 myResult.calculateQuotient(this, pValue);
768
769 /* return the result */
770 return myResult;
771 }
772
773 /**
774 * Divides the value by the amount given. The scale remains the same.
775 *
776 * @param pValue the value to divide by.
777 */
778 public void divide(final long pValue) {
779 /* Multiply the value */
780 theValue /= pValue;
781 }
782
783 /**
784 * Returns a new Decimal whose value is the integral part of (this / pValue).
785 *
786 * @param pValue the value to divide by.
787 * @return the resulting Decimal
788 * @see BigDecimal#divide(BigDecimal)
789 */
790 public OceanusDecimal divideToIntegralValue(final OceanusDecimal pValue) {
791 /* Create the new decimal at the correct scale */
792 final OceanusDecimal myResult = new OceanusDecimal();
793 myResult.setValue(0, theScale);
794
795 /* Calculate the quotient */
796 myResult.calculateQuotient(this, pValue);
797
798 /* Extract the integral part of the result */
799 myResult.setValue(getIntegral(), 0);
800
801 /* return the result */
802 return myResult;
803 }
804
805 /**
806 * Returns a new Decimal whose value is (this / pValue), and whose scale is the same as this
807 * Decimal.
808 *
809 * @param pValue the value to divide by.
810 * @return the resulting Decimal
811 * @see BigDecimal#remainder
812 */
813 public OceanusDecimal remainder(final OceanusDecimal pValue) {
814 /* Create the new decimal at the correct scale */
815 final OceanusDecimal myQuotient = new OceanusDecimal();
816 myQuotient.setValue(0, theScale);
817
818 /* Calculate the quotient */
819 myQuotient.calculateQuotient(this, pValue);
820
821 /* Extract the integral part of the result */
822 myQuotient.setValue(getIntegral(), 0);
823
824 /* Re-multiply by the divisor and adjust to correct scale */
825 final OceanusDecimal myWhole = myQuotient.multiply(pValue);
826 myWhole.setValue(adjustDecimals(myWhole.unscaledValue(), theScale
827 - pValue.scale()), theScale);
828
829 /* Calculate the result */
830 final OceanusDecimal myResult = new OceanusDecimal(this);
831 myResult.subtractValue(myWhole);
832
833 /* return the result */
834 return myResult;
835 }
836
837 /**
838 * Convert the value into a BigDecimal.
839 *
840 * @return the value as a BigDecimal
841 */
842 public BigDecimal toBigDecimal() {
843 /* return the BigDecimal value */
844 return new BigDecimal(toString());
845 }
846
847 /**
848 * Convert the value into a Double.
849 *
850 * @return the value as a double
851 * @see BigDecimal#doubleValue
852 */
853 public double doubleValue() {
854 /* Format the string */
855 final String myString = toString();
856
857 /* return the double value */
858 return Double.parseDouble(myString);
859 }
860
861 /**
862 * Convert the value into a Float.
863 *
864 * @return the value as a float
865 * @see BigDecimal#floatValue
866 */
867 public float floatValue() {
868 /* Format the string */
869 final String myString = toString();
870
871 /* return the float value */
872 return Float.parseFloat(myString);
873 }
874
875 /**
876 * Convert the value into a BigInteger.
877 *
878 * @return the value as a BigInteger
879 * @see BigDecimal#toBigInteger
880 */
881 public BigInteger toBigInteger() {
882 /* return the BigInteger value */
883 return new BigInteger(Long.toString(getIntegral()));
884 }
885
886 /**
887 * Convert the value into a long.
888 *
889 * @return the value as a long
890 * @see BigDecimal#longValue
891 */
892 public long longValue() {
893 /* return the long value */
894 return getIntegral();
895 }
896
897 /**
898 * Convert the value into an integer.
899 *
900 * @return the value as an integer
901 * @see BigDecimal#intValue
902 */
903 public int intValue() {
904 /* return the integer value */
905 return (int) getIntegral();
906 }
907
908 /**
909 * Convert the value into a short.
910 *
911 * @return the value as a short
912 * @see BigDecimal#shortValue
913 */
914 public short shortValue() {
915 /* return the short value */
916 return (short) getIntegral();
917 }
918
919 /**
920 * Convert the value into a byte.
921 *
922 * @return the value as a byte
923 * @see BigDecimal#byteValue
924 */
925 public byte byteValue() {
926 /* return the byte value */
927 return (byte) getIntegral();
928 }
929
930 /**
931 * Check for fractional part on conversion.
932 */
933 public void checkFractionalZero() {
934 /* If we have a fractional part */
935 if (getFractional() != 0) {
936 throw new ArithmeticException("Decimal has fractional part");
937 }
938 }
939
940 /**
941 * Convert the value into a BigInteger, checking for loss of information.
942 *
943 * @return the value as a BigInteger
944 * @see BigDecimal#toBigIntegerExact
945 */
946 public BigInteger toBigIntegerExact() {
947 /* Check fractional is zero */
948 checkFractionalZero();
949
950 /* return the BigInteger value */
951 return toBigInteger();
952 }
953
954 /**
955 * Convert the value into a long, checking for loss of information.
956 *
957 * @return the value as a long
958 * @see BigDecimal#longValueExact
959 */
960 public long longValueExact() {
961 /* Check fractional is zero */
962 checkFractionalZero();
963
964 /* return the long value */
965 return longValue();
966 }
967
968 /**
969 * Convert the value into an integer, checking for loss of information.
970 *
971 * @return the value as an integer
972 * @see BigDecimal#intValueExact
973 */
974 public int intValueExact() {
975 /* Check fractional is zero */
976 checkFractionalZero();
977
978 /* If we have a fractional part */
979 final long myValue = getIntegral();
980 if ((myValue > Integer.MAX_VALUE)
981 || (myValue < Integer.MIN_VALUE)) {
982 throw new ArithmeticException(ERROR_RANGE);
983 }
984
985 /* return the integer value */
986 return (int) myValue;
987 }
988
989 /**
990 * Convert the value into a short, checking for loss of information.
991 *
992 * @return the value as a short
993 * @see BigDecimal#shortValueExact
994 */
995 public short shortValueExact() {
996 /* Check fractional is zero */
997 checkFractionalZero();
998
999 /* If we have a fractional part */
1000 final long myValue = getIntegral();
1001 if ((myValue > Short.MAX_VALUE)
1002 || (myValue < Short.MIN_VALUE)) {
1003 throw new ArithmeticException(ERROR_RANGE);
1004 }
1005
1006 /* return the short value */
1007 return (short) myValue;
1008 }
1009
1010 /**
1011 * Convert the value into a byte, checking for loss of information.
1012 *
1013 * @return the value as a byte
1014 * @see BigDecimal#byteValueExact
1015 */
1016 public byte byteValueExact() {
1017 /* Check fractional is zero */
1018 checkFractionalZero();
1019
1020 /* If we have a fractional part */
1021 final long myValue = getIntegral();
1022 if ((myValue > Byte.MAX_VALUE)
1023 || (myValue < Byte.MIN_VALUE)) {
1024 throw new ArithmeticException(ERROR_RANGE);
1025 }
1026
1027 /* return the byte value */
1028 return (byte) myValue;
1029 }
1030
1031 @Override
1032 public boolean equals(final Object pThat) {
1033 /* Handle trivial cases */
1034 if (this == pThat) {
1035 return true;
1036 }
1037 if (pThat == null) {
1038 return false;
1039 }
1040
1041 /* Make sure that the object is the same class */
1042 if (getClass() != pThat.getClass()) {
1043 return false;
1044 }
1045
1046 /* Cast as decimal */
1047 final OceanusDecimal myThat = (OceanusDecimal) pThat;
1048
1049 /* Check value and scale */
1050 return theValue == myThat.theValue
1051 && theScale == myThat.theScale;
1052 }
1053
1054 @Override
1055 public int hashCode() {
1056 return Objects.hash(theValue, theScale);
1057 }
1058
1059 @Override
1060 public int compareTo(final OceanusDecimal pThat) {
1061 /* Handle trivial case */
1062 if (this.equals(pThat)) {
1063 return 0;
1064 }
1065
1066 /* If there is no difference in scale */
1067 final int myScaleDiff = scale()
1068 - pThat.scale();
1069 if (myScaleDiff == 0) {
1070 /* Just compare unscaled value */
1071 if (theValue == pThat.theValue) {
1072 return 0;
1073 }
1074 return (theValue < pThat.theValue)
1075 ? -1
1076 : 1;
1077 }
1078
1079 /* Compare integral values */
1080 long myDiff = getIntegral()
1081 - pThat.getIntegral();
1082 if (myDiff != 0) {
1083 return (myDiff < 0)
1084 ? -1
1085 : 1;
1086 }
1087
1088 /* Access fractional parts */
1089 long myFirst = getFractional();
1090 long mySecond = pThat.getFractional();
1091
1092 /* Adjust to same maximum scale */
1093 if (myScaleDiff < 0) {
1094 myFirst = adjustDecimals(myFirst, -myScaleDiff);
1095 } else {
1096 mySecond = adjustDecimals(mySecond, myScaleDiff);
1097 }
1098
1099 /* Compare fractional values */
1100 myDiff = myFirst
1101 - mySecond;
1102 if (myDiff != 0) {
1103 return (myDiff < 0)
1104 ? -1
1105 : 1;
1106 }
1107
1108 /* Equal to all intents and purposes */
1109 return 0;
1110 }
1111
1112 /**
1113 * Build powers of ten.
1114 *
1115 * @param pMax maximum power of ten
1116 * @return array of powers of ten
1117 */
1118 private static long[] getPowersOfTen(final int pMax) {
1119 /* Allocate the array */
1120 final long[] myArray = new long[pMax + 2];
1121
1122 /* Initialise array */
1123 long myValue = 1;
1124 myArray[0] = myValue;
1125
1126 /* Loop through array */
1127 for (int i = 1; i <= pMax + 1; i++) {
1128 /* Adjust value and record it */
1129 myValue *= RADIX_TEN;
1130 myArray[i] = myValue;
1131 }
1132
1133 /* Return the array */
1134 return myArray;
1135 }
1136
1137 /**
1138 * Convert the Decimal to a byte array.
1139 *
1140 * @return the byte array
1141 */
1142 public byte[] toBytes() {
1143 final byte[] myValue = OceanusDataConverter.longToByteArray(unscaledValue());
1144 final byte[] myResult = Arrays.copyOf(myValue, myValue.length + 1);
1145 myResult[myValue.length] = (byte) scale();
1146 return myResult;
1147 }
1148 }