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