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