View Javadoc
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 =&gt; 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 }