image
 
image
UMath.java


/*::.
==================================================================================================================================
=================================================¦ Copyright © 2007 Allen Baker ¦=================================================
                                                 +------------------------------+
File:       UMath.java
Originator: Allen Baker (2007.01.26 21:45)
LayoutRev:  5
================================================================================================================================== */



/*.
==========================================================================================
Package
------------------------------------------------------------------------------------------ */
package cosmicabyss.com.lib;



/*.
==========================================================================================
Imports
------------------------------------------------------------------------------------------ */
import java.io.*;
import java.util.*;
import java.math.*;



/*::
======================================================================================================================== *//**
This class is intended to act as a full, and more powerful replacement for the methods of Java's Math class or as a
source of Math-related static utility methods.<P>

The Java Math class (Math) is final, meaning that you cannot add methods to it or improve it in any way by creating a
subclass of it. This is an annoyance because it forces the user to create a separate Math utility class containing any
utility methods the user needs for Math, and to then switch back and forth between the Math class and the Math utility
class.<P>

This class provides static methods that are equivalent to all the Math class's methods. In other words, it replicates
the Math class's entire API. UMath goes further by providing additional methods not found in the Math class. These
additional methods greatly extend the power of UMath beyond that of Math.<P>

Taken together, the above mentioned characteristics of UMath result in a class that can be used as a more powerful
replacement for Math's API.<P>

The most obvious differences between this class and the standard Java Math class are:<P>
   => While providing exactly the same methods as the Math class, this class also offers numerous additional methods
      That extend the Math class functionality.

<P>
   <DL>
      <DT>
         <B>
            Example usage:
         </B>
         <DD>
            <BLOCKQUOTE>
               <PRE id="unindent">
                  no example provided
               </PRE>
            </BLOCKQUOTE>
         </DD>
      </DT>
      <DT>
         <B>
            View Source:
         </B>
         <DD>
            <A href="UMath.java.html">
               uMath.java
            </A>
         </DD>
      </DT>
      <DT>
         <B>
            Author:
         </B>
         <DD>
            <A href="mailto:sourcecode.v01@cosmicabyss.com">
               Allen Baker
            </A>
         </DD>
      </DT>
   </DL>
*//*
======================================================================================================================== */
public class UMath
   {
   /*.
   ==========================================================================================
   Class Constants
      <BLOCKQUOTE>
         <PRE id="unindent">
            ONE_K   : kilo (1024)^1
            ONE_MEG : mega (1024)^2
            ONE_GIG : giga (1024)^3
            PHI     : golden ratio
            E       : the base of the natural logarithms
            PI      : the ratio of the circumference of a circle to its
                      diameter
         </PRE>
      </BLOCKQUOTE>
   ------------------------------------------------------------------------------------------ */
   public static final int     ONE_K   = 1024;
   public static final int     ONE_MEG = 1024*1024;
   public static final int     ONE_GIG = 1024*1024*1024;
   public static final double  PHI     = 1.618033988749894848204586834365638;
   public static final double  E       = 2.718281828459045235360287471352662;
   public static final double  PI      = 3.141592653589793238462643383279502;


   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Protected  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Private  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Inner Classes  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Public Static Methods  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */



   /*:.
   ==============================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  The Math API  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ============================================================================================================== */



   public static double sin(double a)
      {
      return Math.sin(a);
      }

   public static double cos(double a)
      {
      return Math.cos(a);
      }

   public static double tan(double a)
      {
      return Math.tan(a);
      }

   public static double asin(double a)
      {
      return Math.asin(a);
      }

   public static double acos(double a)
      {
      return Math.acos(a);
      }

   public static double atan(double a)
      {
      return Math.atan(a);
      }

   public static double toRadians(double angdeg)
      {
      return Math.toRadians(angdeg);
      }

   public static double toDegrees(double angrad)
      {
      return Math.toDegrees(angrad);
      }

   public static double exp(double a)
      {
      return Math.exp(a);
      }

   public static double log(double a)
      {
      return Math.log(a);
      }

   public static double log10(double a)
      {
      return Math.log10(a);
      }

   public static double sqrt(double a)
      {
      return Math.sqrt(a);
      }

   public static double cbrt(double a)
      {
      return Math.cbrt(a);
      }

   public static double IEEEremainder(double f1, double f2)
      {
      return Math.IEEEremainder(f1, f2);
      }

   public static double ceil(double a)
      {
      return Math.ceil(a);
      }

   public static double floor(double a)
      {
      return Math.floor(a);
      }

   public static double rint(double a)
      {
      return Math.rint(a);
      }

   public static double atan2(double y, double x)
      {
      return Math.atan2(y, x);
      }

   public static double pow(double a, double b)
      {
      return Math.pow(a, b);
      }

   public static int round(float a)
      {
      return Math.round(a);
      }

   public static long round(double a)
      {
      return Math.round(a);
      }

   public static double random()
      {
      return Math.random();
      }

   public static int abs(int a)
      {
      return Math.abs(a);
      }

   public static long abs(long a)
      {
      return Math.abs(a);
      }

   public static float abs(float a)
      {
      return Math.abs(a);
      }

   public static double abs(double a)
      {
      return Math.abs(a);
      }

   public static int max(int a, int b)
      {
      return Math.max(a,b);
      }

   public static long max(long a, long b)
      {
      return Math.max(a,b);
      }

   public static float max(float a, float b)
      {
      return Math.max(a,b);
      }

   public static double max(double a, double b)
      {
      return Math.max(a,b);
      }

   public static int min(int a, int b)
      {
      return Math.min(a,b);
      }

   public static long min(long a, long b)
      {
      return Math.min(a,b);
      }

   public static float min(float a, float b)
      {
      return Math.min(a,b);
      }

   public static double min(double a, double b)
      {
      return Math.min(a,b);
      }

   public static double ulp(double d)
      {
      return Math.ulp(d);
      }

   public static float ulp(float f)
      {
      return Math.ulp(f);
      }

   public static double signum(double d)
      {
      return Math.signum(d);
      }

   public static float signum(float f)
      {
      return Math.signum(f);
      }

   public static double sinh(double x)
      {
      return Math.sinh(x);
      }

   public static double cosh(double x)
      {
      return Math.cosh(x);
      }

   public static double tanh(double x)
      {
      return Math.tanh(x);
      }

   public static double hypot(double x, double y)
      {
      return Math.hypot(x, y);
      }

   public static double expm1(double x)
      {
      return Math.expm1(x);
      }

   public static double log1p(double x)
      {
      return Math.log1p(x);
      }

   public static double copySign(double magnitude, double sign)
      {
      return Math.copySign(magnitude, sign);
      }

   public static float copySign(float magnitude, float sign)
      {
      return Math.copySign(magnitude, sign);
      }

   public static int getExponent(float f)
      {
      return Math.getExponent(f);
      }

   public static int getExponent(double d)
      {
      return Math.getExponent(d);
      }

   public static double nextAfter(double start, double direction)
      {
      return Math.nextAfter(start, direction);
      }

   public static float nextAfter(float start, double direction)
      {
      return Math.nextAfter(start, direction);
      }

   public static double nextUp(double d)
      {
      return Math.nextUp(d);
      }

   public static float nextUp(float f)
      {
      return Math.nextUp(f);
      }

   public static double scalb(double d, int scaleFactor)
      {
      return Math.scalb(d, scaleFactor);
      }

   public static float scalb(float f, int scaleFactor)
      {
      return Math.scalb(f, scaleFactor);
      }



   /*:.
   ==============================================================================================================
   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[  The Extensions  ]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   ============================================================================================================== */



   /*:                                    :METHOD:000:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns the smallest of an arbitrary number of values.

   <P><B>Implementation: </B><A HREF="UMath.java.html#000">View source</A>

   @return
      This method returns the smallest number in a array of numbers. If the array of numbers is empty,
      this method will return Double.MAX_VALUE.

   @param
      pNumbers is an array of numbers. They can be any primitive numeric types and they do not all have
      to be the same numeric type. The primitive types are byte, double, float, int, long, and short.
      Whatever the numbers in the array are, they are all converted to double for this operation. The
      specific semantics of the conversion from the numeric value of a particular Number implementation
      to a given primitive type is defined by the Number implementation in question. For platform
      classes, the conversion is often analogous to a narrowing primitive conversion or a widening
      primitive conversion as defined in The Java™ Language Specification for converting between
      primitive types. Therefore, conversions may lose information about the overall magnitude of a
      numeric value, may lose precision, and may even return a result of a different sign than the
      input. See the documentation of a given Number implementation for conversion details.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double min(Object... pNumbers)
      {
      double result = Double.MAX_VALUE;
      for (Object obj: pNumbers)
         {
         double dbl = ((Number)obj).doubleValue();
         result = min(result, dbl);
         }
      return result;
      }



   /*:                                    :METHOD:001:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns the largest of an arbitrary number of values.

   <P><B>Implementation: </B><A HREF="UMath.java.html#001">View source</A>

   @return
      This method returns the largest number in a array of numbers. If the array of numbers is empty,
      this method will return Double.MIN_VALUE.

   @param
      pNumbers is an array of numbers. They can be any primitive numeric types and they do not all have
      to be the same numeric type. The primitive types are byte, double, float, int, long, and short.
      Whatever the numbers in the array are, they are all converted to double for this operation. The
      specific semantics of the conversion from the numeric value of a particular Number implementation
      to a given primitive type is defined by the Number implementation in question. For platform
      classes, the conversion is often analogous to a narrowing primitive conversion or a widening
      primitive conversion as defined in The Java™ Language Specification for converting between
      primitive types. Therefore, conversions may lose information about the overall magnitude of a
      numeric value, may lose precision, and may even return a result of a different sign than the
      input. See the documentation of a given Number implementation for conversion details.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double max(Object... pNumbers)
      {
      double result = Double.MIN_VALUE;
      for (Object obj: pNumbers)
         {
         double dbl = ((Number)obj).doubleValue();
         result = max(result, dbl);
         }
      return result;
      }



   /*:                                    :METHOD:002:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns pVal unless pVal is less than pMin or greater than pMax. If pVal is less than
   pMin, this method returns pMin. If pVal is greater than pMax, this method returns pMax.

   <P><B>Implementation: </B><A HREF="UMath.java.html#002">View source</A>

   @return
      pVal forced into the range pMin..pMax inclusive.

   @param
      pVal is the value to force in range
   @param
      pMin is the low end of the range
   @param
      pMax is the high end of the range
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int forceIntoRange(int pVal, int pMin, int pMax)
      {
      pVal = UMath.max(pVal,pMin);
      pVal = UMath.min(pVal,pMax);
      return pVal;
      }
   public static long forceIntoRange(long pVal, long pMin, long pMax)
      {
      pVal = UMath.max(pVal,pMin);
      pVal = UMath.min(pVal,pMax);
      return pVal;
      }
   public static float forceIntoRange(float pVal, float pMin, float pMax)
      {
      pVal = UMath.max(pVal,pMin);
      pVal = UMath.min(pVal,pMax);
      return pVal;
      }
   public static double forceIntoRange(double pVal, double pMin, double pMax)
      {
      pVal = UMath.max(pVal,pMin);
      pVal = UMath.min(pVal,pMax);
      return pVal;
      }



   /*:                                    :METHOD:003:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns true if pVal is in the range pMin .. PMax, inclusive.

   <P><B>Implementation: </B><A HREF="UMath.java.html#003">View source</A>

   @return
      True if pVal is in the range pMin..pMax inclusive. Otherwise, false.

   @param
      pVal is the value to test
   @param
      pMin is the low end of the range
   @param
      pMax is the high end of the range
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static boolean isInRange(int pVal, int pMin, int pMax)
      {
      return ((pMin <= pVal) && (pVal <= pMax));
      }
   public static boolean isInRange(long pVal, long pMin, long pMax)
      {
      return ((pMin <= pVal) && (pVal <= pMax));
      }
   public static boolean isInRange(float pVal, float pMin, float pMax)
      {
      return ((pMin <= pVal) && (pVal <= pMax));
      }
   public static boolean isInRange(double pVal, double pMin, double pMax)
      {
      return ((pMin <= pVal) && (pVal <= pMax));
      }



   /*:                                    :METHOD:004:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method decodes a String into an Long. It accepts decimal numbers, numbers given by the
   following grammar:
      <BLOCKQUOTE>
         <PRE id="unindent">
            DecodableString := [Sign][leading zeros]IntegerDigits
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#004">View source</A>

   @return
      A long holding the value represented by pStr.

   @param
      pStr is the String representation of a decimal long to decode.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type> long decodeDecimalLong(Type pStr) throws Exception
      {
      return (Long.decode(UString.removeLeadingZeros(pStr))).longValue();
      }



   /*:                                    :METHOD:005:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method decodes a String into an Integer. It accepts decimal numbers, numbers given by the
   following grammar:
      <BLOCKQUOTE>
         <PRE id="unindent">
            DecodableString := [Sign][leading zeros]IntegerDigits
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#005">View source</A>

   @return
      An integer holding the value represented by pStr.

   @param
      pStr is the String representation of a decimal integer to decode.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type> int decodeDecimalInt(Type pStr) throws Exception
      {
      return (Integer.decode(UString.removeLeadingZeros(pStr))).intValue();
      }



   /*:                                    :METHOD:006:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method decodes a String into an double. It accepts decimal numbers, numbers given by the
   following grammar:
      <BLOCKQUOTE>
         <PRE id="unindent">
            DecodableString := [Sign][leading zeros]IntegerDigits[.][IntegerDigits]
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#006">View source</A>

   @return
      A double holding the value represented by pStr.

   @param
      pStr is the String representation of a double number to decode.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static <Type> double decodeDecimalDouble(Type pStr) throws Exception
      {
      return (Double.parseDouble(UString.removeLeadingZeros(pStr)));
      }



   /*:                                    :METHOD:007:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method converts a decimal number to a percentage.<P>

   For example, this method would convert the dicmal number 0.023 to 2.3

   <P><B>Implementation: </B><A HREF="UMath.java.html#007">View source</A>

   @return
      A percentage representation of the decimal number

   @param
      pDecimal is the decimal number to convert to a percentage
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double toPct(double pDecimal)
      {
      return pDecimal * 100.0;
      }



   /*:                                    :METHOD:008:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method converts a percentage to a decimal number.<P>

   For example, this method would convert the percentage 2.3 to 0.023

   <P><B>Implementation: </B><A HREF="UMath.java.html#008">View source</A>

   @return
      A decimal number representation of the percentage

   @param
      pPercentage is the percentage to convert to a decimal number
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double fromPct(double pPercentage)
      {
      return pPercentage / 100.0;
      }



   /*:                                    :METHOD:009:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method rounds a double to the nearest specified number of decimal places. Here are some
   examples:
      <BLOCKQUOTE>
         <PRE id="unindent">
            round( 3.141592653589793, 0 )  =  3.0
            round( 3.141592653589793, 1 )  =  3.1
            round( 3.141592653589793, 2 )  =  3.14
            round( 3.141592653589793, 3 )  =  3.142
            round( 3.141592653589793, 4 )  =  3.1416
            round( 3.141592653589793, 5 )  =  3.14159
            round( 3.141592653589793, 6 )  =  3.141593
            round( 3.141592653589793, 7 )  =  3.1415927
            round( 3.141592653589793, 8 )  =  3.14159265
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#009">View source</A>

   @return
      The number rounded to the nearest specified number of decimal places.

   @param
      pValue the number to be rounded
   @param
      pPlaces the specified number of decimal places
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double round(double pValue, int pPlaces)
      {
      double factor = UMath.pow(10,pPlaces);
      return (double)UMath.round(pValue*factor) / factor;
      }



   /*:                                    :METHOD:010:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method rounds a float to the nearest specified number of decimal places. Here are some
   examples:
      <BLOCKQUOTE>
         <PRE id="unindent">
            round( 3.141592653589793, 0 )  =  3.0
            round( 3.141592653589793, 1 )  =  3.1
            round( 3.141592653589793, 2 )  =  3.14
            round( 3.141592653589793, 3 )  =  3.142
            round( 3.141592653589793, 4 )  =  3.1416
            round( 3.141592653589793, 5 )  =  3.14159
            round( 3.141592653589793, 6 )  =  3.141593
            round( 3.141592653589793, 7 )  =  3.1415927
            round( 3.141592653589793, 8 )  =  3.14159265
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#010">View source</A>

   @return
      The number rounded to the nearest specified number of decimal places.

   @param
      pValue the number to be rounded
   @param
      pPlaces the specified number of decimal places
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static float round(float pValue, int pPlaces)
      {
      return (float)UMath.round((double)pValue,pPlaces);
      }



   /*:                                    :METHOD:011:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns the integer portion of a double.

   <P><B>Implementation: </B><A HREF="UMath.java.html#011">View source</A>

   @return
      The integer portion of the number.

   @param
      pValue the number to truncate
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int trunc(double pValue)
      {
      return (int)pValue;
      }



   /*:                                    :METHOD:012:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns the integer portion of a float.

   <P><B>Implementation: </B><A HREF="UMath.java.html#012">View source</A>

   @return
      The integer portion of the number.

   @param
      pValue the number to truncate
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int trunc(float pValue)
      {
      return (int)pValue;
      }



   /*:                                    :METHOD:013:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method prints out comma-separated list of the values in a byte[] along with their array index.

   <P><B>Implementation: </B><A HREF="UMath.java.html#013">View source</A>

   @param
      pBytes is the byte[] to print the values of
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static void print(byte[] pBytes) throws Exception
      {
      for (int i=0; i<pBytes.length; i++)
         {
         System.out.println(i + "," + UMath.b2i(pBytes[i]));
         }
      }



   /*:                                    :METHOD:014:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method converts the value stored in a byte to an integer without the sign extension that
   happens when a cast is used to do the same thing. In other words, it treats the byte as an unsigned
   value in the range 0 .. 255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#014">View source</A>

   @param
      pByte is the byte to convert to an integer.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int b2i(byte pByte) throws Exception
      {
      return (pByte & 0x7F) + ((pByte < 0) ? 128 : 0);
      }



   /*:                                    :METHOD:015:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method computes the distribution of values in a byte[]. The byte[] is treated as an array of
   unsigned bytes so the possible values in each byte are in the range 0..255. This method creates a
   new byte[] that is 256 bytes long - with one element for each possible byte value 0..255. Into each
   ith element is placed a count of the number of times I is found in the input byte[]. The array of
   counts is the byte[] that is returned.

   <P><B>Implementation: </B><A HREF="UMath.java.html#015">View source</A>

   @return
      A byte[] in which each ith element contains a count of the number of elements in the input array
      that have the value of i.

   @param
      pBytes is the array for which to compute the distribution.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static byte[] distribution(byte[] pBytes) throws Exception
      {
      byte[]  x = new byte[256];
      Arrays.fill(x,(byte)0);
      for (int i=0; i<pBytes.length; i++)
         {
         int  n = UMath.b2i(pBytes[i]);
         x[n]++;
         }
      return x;
      }



   /*:                                    :METHOD:016:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method sums up the values in the input array. The input array is treated as an array of
   unsigned bytes, so the value in each element is in the range 0..255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#016">View source</A>

   @return
      An integer containing a summation of the unsigned bytes in the input byte[].

   @param
      pBytes is the array for which to compute the sum.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int sum(byte[] pBytes) throws Exception
      {
      int  sum = 0;
      for (int i=0; i<pBytes.length; i++)
         {
         sum += UMath.b2i(pBytes[i]);
         }
      return sum;
      }



   /*:                                    :METHOD:017:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method sums up the squares or the values in the input array. The input array is treated as an
   array of unsigned bytes, so the value in each element is in the range 0..255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#017">View source</A>

   @return
      An integer containing a summation squares of the unsigned bytes in the input byte[].

   @param
      pBytes is the array for which to compute the sum of squares.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int sumOfSquares(byte[] pBytes) throws Exception
      {
      int  sum = 0;
      for (int i=0; i<pBytes.length; i++)
         {
         sum += UMath.b2i(pBytes[i]) * UMath.b2i(pBytes[i]);
         }
      return sum;
      }



   /*:                                    :METHOD:018:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method computes the average of the values in the input array. The input array is treated as an
   array of unsigned bytes, so the value in each element is in the range 0..255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#018">View source</A>

   @return
      A double containing the average of the unsigned bytes in the input byte[].

   @param
      pBytes is the array for which to compute the average.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double average(byte[] pBytes) throws Exception
      {
      return (double)UMath.sum(pBytes) / (double)pBytes.length;
      }

   public static double average(int[] pInt)
      {
      int  i   = 0;
      int  sum = 0;
      for (i=0; i<pInt.length; i++)
         {
         sum += pInt[i];
         }
      return (double)sum / (double)i;
      }



   /*:                                    :METHOD:019:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method computes the variance of the values in the input array. The input array is treated as an
   array of unsigned bytes, so the value in each element is in the range 0..255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#019">View source</A>

   @return
      A double containing the variance of the unsigned bytes in the input byte[].

   @param
      pBytes is the array for which to compute the variance.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double variance(byte[] pBytes) throws Exception
      {
      double  n    = (double)pBytes.length;
      double  sum  = (double)UMath.sum(pBytes);
      double  sum2 = (double)UMath.sumOfSquares(pBytes);
      return (n*sum2 - sum*sum) / (n*n);   // (n*sum2 - sum*sum) / (n*(n-1))
      }



   /*:                                    :METHOD:020:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method computes the standard deviation of the values in the input array. The input array is
   treated as an array of unsigned bytes, so the value in each element is in the range 0..255.

   <P><B>Implementation: </B><A HREF="UMath.java.html#020">View source</A>

   @return
      A double containing the standard deviation of the unsigned bytes in the input byte[].

   @param
      pBytes is the array for which to compute the standard deviation.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double stdDev(byte[] pBytes) throws Exception
      {
      return UMath.sqrt(UMath.variance(pBytes));
      }



   /*:                                    :METHOD:021:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method applies the specified binary operation to each group of adjacent input byte[] elements
   starting at the left (begining) of the array and moving rightwards across the array. As the process
   moves across the array from left to right, the result of each operation is placed into the leading
   (RIGHT) element of the group of adjacent elements in the array. The input array is treated as an
   array of unsigned bytes, so the value in each element is in the range 0..255.<P>

   <P><B>Implementation: </B><A HREF="UMath.java.html#021">View source</A>

   @return
      A new byte[] with each element replaced with the result of the operation.

   @param
      pBytes is the array to which the operation is applied to adjacent elements.
   @param
      pOperator is the binary operation to apply and may be any one of the following characters: + - *
      & | ^
   @param
      pGrpSize is the number of elements to group together for each application of the operation.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static byte[] LopR(byte[] pBytes, char pOperator, int pGrpSize) throws Exception
      {
      /*.
      ==========================================================================================
      We are not going to modify the input array directly. Instead, we make a copy of the input
      array into which we will put the results of the computations.
      ------------------------------------------------------------------------------------------ */
      byte[]  copy = new byte[pBytes.length];
      System.arraycopy(pBytes,0,copy,0,pBytes.length);
      /*.
      ==========================================================================================
      Create an index to select each element of the array that will be involved in each
      iteration of the computation.
      ------------------------------------------------------------------------------------------ */
      int[]  idx = new int[pGrpSize];
      int    nxt = 0;
      for (int i=0; i<idx.length; i++)
         {
         idx[i] = nxt;
         nxt    = UMath.inc(nxt,copy.length);
         }
      /*.
      ==========================================================================================
      For as many iterations as there are elements in the array ...
      ------------------------------------------------------------------------------------------ */
      for (int i=0; i<copy.length; i++)
         {
         /*.
         ==========================================================================================
         Apply the binary operator across all the elements of a group
         ------------------------------------------------------------------------------------------ */
         int result = UMath.b2i(copy[idx[0]]);
         for (int j=1; j<idx.length; j++)
            {
            /*.
            ==========================================================================================
            Apply the binary operator
            ------------------------------------------------------------------------------------------ */
            switch (pOperator)
               {
               case '+' : result += UMath.b2i(copy[idx[j]]); break;
               case '-' : result -= UMath.b2i(copy[idx[j]]); break;
               case '*' : result *= UMath.b2i(copy[idx[j]]); break;
               case '&' : result &= UMath.b2i(copy[idx[j]]); break;
               case '|' : result |= UMath.b2i(copy[idx[j]]); break;
               case '^' : result ^= UMath.b2i(copy[idx[j]]); break;
               default  :
                  {
                  throw new Exception(pOperator + " is an invalid operation");
                  }
               }
            }
         /*.
         ==========================================================================================
         Store the result into the rightmost element of the group
         ------------------------------------------------------------------------------------------ */
         copy[idx[idx.length-1]] = (byte)result;
         /*.
         ==========================================================================================
         Increment the group indexes
         ------------------------------------------------------------------------------------------ */
         for (int j=0; j<idx.length; j++)
            {
            idx[j] = UMath.inc(idx[j],copy.length);
            }
         }
      /*.
      ==========================================================================================
      Return the new array
      ------------------------------------------------------------------------------------------ */
      return copy;
      }



   /*:                                    :METHOD:022:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method applies the specified binary operation to each group of adjacent input byte[] elements
   starting at the right (ending) of the array and moving leftwards across the array. As the process
   moves across the array from right to left, the result of each operation is placed into the leading
   (LEFT) element of the group of adjacent elements in the array. The input array is treated as an
   array of unsigned bytes, so the value in each element is in the range 0..255.<P>

   <P><B>Implementation: </B><A HREF="UMath.java.html#022">View source</A>

   @return
      A new byte[] with each element replaced with the result of the operation.

   @param
      pBytes is the array to which the operation is applied to adjacent elements.
   @param
      pOperator is the binary operation to apply and may be any one of the following characters: + - *
      & | ^
   @param
      pGrpSize is the number of elements to group together for each application of the operation.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static byte[] RopL(byte[] pBytes, char pOperator, int pGrpSize) throws Exception
      {
      /*.
      ==========================================================================================
      We are not going to modify the input array directly. Instead, we make a copy of the input
      array into which we will put the results of the computations.
      ------------------------------------------------------------------------------------------ */
      byte[]  copy = new byte[pBytes.length];
      System.arraycopy(pBytes,0,copy,0,pBytes.length);
      /*.
      ==========================================================================================
      Create an index to select each element of the array that will be involved in each
      iteration of the computation.
      ------------------------------------------------------------------------------------------ */
      int[]  idx = new int[pGrpSize];
      int    nxt = copy.length-1;
      for (int i=0; i<idx.length; i++)
         {
         idx[i] = nxt;
         nxt    = UMath.dec(nxt,copy.length);
         }
      /*.
      ==========================================================================================
      For as many iterations as there are elements in the array ...
      ------------------------------------------------------------------------------------------ */
      for (int i=0; i<copy.length; i++)
         {
         /*.
         ==========================================================================================
         Apply the binary operator across all the elements of a group
         ------------------------------------------------------------------------------------------ */
         int result = UMath.b2i(copy[idx[0]]);
         for (int j=1; j<idx.length; j++)
            {
            /*.
            ==========================================================================================
            Apply the binary operator
            ------------------------------------------------------------------------------------------ */
            switch (pOperator)
               {
               case '+' : result += UMath.b2i(copy[idx[j]]); break;
               case '-' : result -= UMath.b2i(copy[idx[j]]); break;
               case '*' : result *= UMath.b2i(copy[idx[j]]); break;
               case '&' : result &= UMath.b2i(copy[idx[j]]); break;
               case '|' : result |= UMath.b2i(copy[idx[j]]); break;
               case '^' : result ^= UMath.b2i(copy[idx[j]]); break;
               default  :
                  {
                  throw new Exception(pOperator + " is an invalid operation");
                  }
               }
            }
         /*.
         ==========================================================================================
         Store the result into the leftmost element of the group
         ------------------------------------------------------------------------------------------ */
         copy[idx[idx.length-1]] = (byte)result;
         /*.
         ==========================================================================================
         Decrement the group indexes
         ------------------------------------------------------------------------------------------ */
         for (int j=0; j<idx.length; j++)
            {
            idx[j] = UMath.dec(idx[j],copy.length);
            }
         }
      /*.
      ==========================================================================================
      Return the new array
      ------------------------------------------------------------------------------------------ */
      return copy;
      }



   /*:                                    :METHOD:023:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method increments an index into an array of size pBound.

   <P><B>Implementation: </B><A HREF="UMath.java.html#023">View source</A>

   @return
      The incremented index.

   @param
      pIdx is the index to increment.
   @param
      pBound is the size of the array that pIdx indexes.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int inc(int pIdx, int pBound)
      {
      return (++pIdx) % pBound;
      }



   /*:                                    :METHOD:024:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method decrements an index into an array of size pBound.

   <P><B>Implementation: </B><A HREF="UMath.java.html#024">View source</A>

   @return
      The decremented index.

   @param
      pIdx is the index to decrement.
   @param
      pBound is the size of the array that pIdx indexes.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static int dec(int pIdx, int pBound)
      {
      return (--pIdx < 0)? pBound-1 : pIdx;
      }



   /*:                                    :METHOD:025:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns a rolling average.<P>
      <BLOCKQUOTE>
         <PRE id="unindent">
            If the period is 7, a value (call it X) is 1/7th of the rolling average
            when it is passed in as the latest measurement (incr 1).  On the next
            call, X becomes 6/49ths of the rolling average or 12.244898% of the
            rolling average. On the 3rd call (incr 3), X becomes 36/343rds of the
            rolling average or 10.4956268% of the rolling average. Etc.

            Incr:   1            2           3            4            5            6

            Mltpl
            of prv
            ratio:  1/7          6/7         6/7          6/7         6/7         6/7

            Ratio:  1/7          6/49        36/343       216/2401    1296/16807  7776/117649

            Pct:    14.2857143%  12.244898%  10.4956268%  8.9962516%  7.7110728%  6.6094909%
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#025">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double rollingAvg(double pLatestMeasurement, double pPrevAvg, int pPeriod)
      {
      return (pLatestMeasurement + (pPrevAvg * (pPeriod - 1))) / pPeriod;
      }



   /*:                                    :METHOD:026:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**

   <P><B>Implementation: </B><A HREF="UMath.java.html#026">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double rollingAvgWithGap(double pLatestMeasurement, double pPrevAvg, int pPeriod, int pGap)
      {
      double  pa = pPrevAvg;
      if (pGap > 0)
         {
         for (int i=0; i<pGap; i++)
            {
            pa = rollingAvg(0, pa, pPeriod);
            }
         }
      return rollingAvg(pLatestMeasurement, pa, pPeriod);
      }



   /*:                                    :METHOD:027:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns true if the argument is an odd number.

   <P><B>Implementation: </B><A HREF="UMath.java.html#027">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static boolean isOdd(int pNum)
      {
      return ((pNum & 1) == 1);
      }



   /*:                                    :METHOD:028:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns true if the argument is an even number.

   <P><B>Implementation: </B><A HREF="UMath.java.html#028">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static boolean isEven(int pNum)
      {
      return ((pNum & 1) == 0);
      }



   /*:                                    :METHOD:029:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns pN mod pD and obeys the Quotient-Remainder Theorem.

   Note: This implementation works on real numbers for pN and pD

   Note: This implementation works on negative numbers for pD

   <P><B>Implementation: </B><A HREF="UMath.java.html#029">View source</A>

   @return
      Mod(n, d) returns the nonnegative (>=0) remainder obtained when n is divided by d. It always
      falls in the range [0...d).

   @param
      PN is the dividend or numerator
   @param
      PD is the divisor or denominator
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double mod(double pN, double pD)
      {
      return realDivMod(pN,pD)[1];
      /*.
      ==========================================================================================

         <BLOCKQUOTE>
            <PRE id="unindent">
               Here's an integer algorithm:
                  return pN - (pD * div(pN, pD));
               Here's another algorithm:
                  return (pN % pD + pD) % pD;
            </PRE>
         </BLOCKQUOTE>

      It's syntactically elegant but it always performs two division operations whereas the
      algorithm implemented above Requires only one division in most cases. In the implemented
      algorithm, the division operation[s] are performed inside the div() method.
      ------------------------------------------------------------------------------------------ */
      }



   /*:                                    :METHOD:030:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns pN div pD and obeys the Quotient-Remainder Theorem.

   Note: This implementation works on real numbers for pN and pD

   Note: This implementation works on negative numbers for pD

   <P><B>Implementation: </B><A HREF="UMath.java.html#030">View source</A>

   @return
      Div(n, d) returns the integer quotient obtained when n is divided by d.

   @param
      PN is the dividend or numerator
   @param
      PD is the divisor or denominator
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double div(double pN, double pD)
      {
      return realDivMod(pN,pD)[0];
      /*.
      ==========================================================================================
      Here's an integer algorithm:
         <BLOCKQUOTE>
            <PRE id="unindent">
               if (pD <= 0)
                  {
                  throw new IllegalArgumentException("(pD = " + pD + ")  Parameter pD must be greater than zero.");
                  }
               long  q = pN/pD;
               if ((pN < 0) && ((pN % pD) != 0))
                  {
                  q = q - 1;
                  }
               return q;
            </PRE>
         </BLOCKQUOTE>
      ------------------------------------------------------------------------------------------ */
      }



   /*:                                    :METHOD:031:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method returns pN div pD and pN mod pD and obeys the Quotient-Remainder Theorem.

   Note: This implementation works on real numbers for pN and pD

   Note: This implementation works on negative numbers for pD

      <BLOCKQUOTE>
         <PRE id="unindent">
            re: Discrete Mathematics with Applications, 4th Edition, S. Epp
            The Quotient-Remainder Theorem is:
               given any integer n and positive integer d, there exists unique integers q and r such that:
                  n = dq + r  AND  0 <= r < d
                     Notice that r is always positive.  The Java % operator returns a negative r when n is
                     negative.  This is why it's not called the "mod" or "modulus" operator, it's called the
                     "remainder" operator.

               If n is positive, the Quotient-Remainder Theorem can be illustrated on the number line as follows:
                    . . . 0    d    2d   3d . . . . . . qd  n . . .
                  <-------|----|----|----|--------------|---|------->
                                                        |_r_|

               If n is negative, the picture changes.  Since n = dq + r, where r >= 0, d must be multiplied by a
               negative integer q to go below n.  Then the nonnegative integer r is added to come back up to n.
               This is illustraded as follows:
                    . . . dq  n . . . . . . -d3  -d2  -d    0 . . .
                  <-------|---|--------------|----|----|----|------->
                          |_r_|

            This method effectively computes and returns q = (n - r) / d  in the 1st element of the array it returns.
            This method effectively computes and returns r = n - dq       in the 2nd element of the array it returns.
         </PRE>
      </BLOCKQUOTE>

   <P><B>Implementation: </B><A HREF="UMath.java.html#031">View source</A>

   @return
      RealDivMod(n, d) returns an array containing the following two values:
         <BLOCKQUOTE>
            <PRE id="unindent">
               [0] contains pN div pD and obeys the Quotient-Remainder Theorem.
               [1] contains pN mod pD and obeys the Quotient-Remainder Theorem.
            </PRE>
         </BLOCKQUOTE>

   @param
      PN is the dividend or numerator
   @param
      PD is the divisor or denominator
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static double[] realDivMod(double pN, double pD)
      {
      /*.
      ==========================================================================================
      Examples of all types of cases we must handle
         <BLOCKQUOTE>
            <PRE id="unindent">
               n   d   n/d     q   qd   r
               5   6   0.8333  0   0    5
               6   5           1   5    1
               -5  6   -.8333  1   6    1
               -6  5           2  10    4
               -5 -6   0.8333  1  -6    1
               -6 -5           2 -10    4
            </PRE>
         </BLOCKQUOTE>
      ------------------------------------------------------------------------------------------ */
      double[]  qr = new double[2];
      /*.
      ==========================================================================================
      Can't divide by zero
      ------------------------------------------------------------------------------------------ */
      if (pD == 0.0)
         {
         throw new IllegalArgumentException("(pD = " + pD + ")  Parameter pD cannot be zero.");
         }
      /*.
      ==========================================================================================
      If they're equal
      ------------------------------------------------------------------------------------------ */
      if (pN == pD)
         {
         qr[0] = 1.0;
         qr[1] = 0.0;
         return qr;
         }
      /*.
      ==========================================================================================
      If their abs val is the same we know that their signs are different because we already
      handled the case where they are equal.
      ------------------------------------------------------------------------------------------ */
      if (UMath.abs(pN) == UMath.abs(pD))
         {
         qr[0] = -1.0;
         qr[1] = 0.0;
         return qr;
         }
      /*.
      ==========================================================================================
      We know that their abs vals are different so now, if they're both negative
      ------------------------------------------------------------------------------------------ */
      if ((pN < 0.0) && (pD < 0.0))
         {
         if (pD < pN)
            {
            qr[0] = 1.0;
            qr[1] = pN - pD;
            return qr;
            }
         }
      /*.
      ==========================================================================================
      Otherwise, here's the "normal" algorithm
         <BLOCKQUOTE>
            <PRE id="unindent">
               double n = pN;
               double d = pD;
               double r = n % d;
               double q = (n - r) / d;
               if ((n < 0.0) && (r != 0.0))
                  {
                  if (d < 0.0)
                     {
                     q = q + 1.0;
                     }
                  else
                     {
                     q = q - 1.0;
                     }
                  r = n - (d * q);
                  }
               qr[0] = q;
               qr[1] = r;
            </PRE>
         </BLOCKQUOTE>
      ------------------------------------------------------------------------------------------ */
      BigDecimal  n = (new BigDecimal(Double.toString(pN), MathContext.DECIMAL128)).setScale(30, BigDecimal.ROUND_HALF_UP);
      BigDecimal  d = (new BigDecimal(Double.toString(pD), MathContext.DECIMAL128)).setScale(30, BigDecimal.ROUND_HALF_UP);
      BigDecimal  r        = n.remainder(d, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
      BigDecimal  tempTerm = n.subtract(r, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
      BigDecimal  q        = tempTerm.divide(d, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
      if ((n.compareTo(BigDecimal.ZERO) < 0) && (r.compareTo(BigDecimal.ZERO) != 0))
         {
         if (d.compareTo(BigDecimal.ZERO) < 0)
            {
            q = q.add(BigDecimal.ONE, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
            }
         else
            {
            q = q.subtract(BigDecimal.ONE, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
            }
         tempTerm = d.multiply(q, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
         r = n.subtract(tempTerm, MathContext.DECIMAL128).setScale(30, BigDecimal.ROUND_HALF_UP);
         }
      qr[0] = q.doubleValue();
      qr[1] = r.doubleValue();
      return qr;
      }



   /*:                                    :METHOD:032:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method finds the greatest common divisor of two integers, pA and pB. The gcd is defined as the
   largest positive integer c that evenly divides both pA and pB (ie. C|pA and c|pB)

   <P><B>Implementation: </B><A HREF="UMath.java.html#032">View source</A>

   @return
      The greatest common divisor of the integer values passed in through the parameters.

   @param
      PA and pB are the integers for which a gcd is computed. Although either pA or pB can be zero,
      they cannot both be zero.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static long gcd(long pA, long pB)
      {
      /*.
      ==========================================================================================
      Can't both be zero because zero can't be a divisor.
      ------------------------------------------------------------------------------------------ */
      if ((pA == 0) && (pB == 0))
         {
         throw new IllegalArgumentException("Both arguments to gcd(a,b) can't be zero because zero can't be a divisor.");
         }
      /*.
      ==========================================================================================
      If pA is a positive integer then gcd(pA, 0) = pA
      ------------------------------------------------------------------------------------------ */
      if (pB==0)
         {
         return pA;
         }
      /*.
      ==========================================================================================
      Using the Euclidean algorithm,
         If pA = pB*q + r (ie. PA mod pB = r) then gcd(pA,pB) = gcd(pB,r)
      ------------------------------------------------------------------------------------------ */
      return gcd(pB,(long)mod(pA, pB));
      }



   /*:                                    :METHOD:033:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method finds the lcm (greatest common divisor) of an arbitrary number of integers.

   <P><B>Implementation: </B><A HREF="UMath.java.html#033">View source</A>

   @return
      The greatest common divisor of the integer values passed in through the parameters.

   @param
      pNumbers is an array of integers for which a gcd is computed. None of them can be zero.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static long gcd(long... pNumbers)
      {
      long result = 1;
      for (long val: pNumbers)
         {
         result = gcd(result, val);
         }
      return result;
      }



   /*:                                    :METHOD:034:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method finds the lcm (least common multiple) of two integers, pA and pB. The lcm is defined as
   the smallest positive integer c that both pA and pB divide evenly (ie. PA|c and pB|c)

   <P><B>Implementation: </B><A HREF="UMath.java.html#034">View source</A>

   @return
      The least common multiple of the integer values passed in through the parameters.

   @param
      PA and pB are the integers for which a lcm is computed. Neither pA or pB can be zero.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static long lcm(long pA, long pB)
      {
      /*.
      ==========================================================================================
      Neither can be zero.
      ------------------------------------------------------------------------------------------ */
      if ((pA == 0) || (pB == 0))
         {
         throw new IllegalArgumentException("Neither argument to lcm(a,b) can be zero.");
         }
      return (pA * pB) / gcd(pA, pB);
      }



   /*:                                    :METHOD:035:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method finds the lcm (least common multiple) of an arbitrary number of integers.

   <P><B>Implementation: </B><A HREF="UMath.java.html#035">View source</A>

   @return
      The least common multiple of the integer values passed in through the parameters.

   @param
      pNumbers is an array of integers for which a lcm is computed. None of them can be zero.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static long lcm(long... pNumbers)
      {
      long result = 1;
      for (long val: pNumbers)
         {
         result = lcm(result, val);
         }
      return result;
      }



   /*:                                    :METHOD:036:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This boilerplate method is used for testing this class and may include any code the developer
   chooses.

   <P><B>Implementation: </B><A HREF="UMath.java.html#036">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static void test() throws Exception
      {
      System.out.println
         (
         "\"HELLO WORLD!\"  I'm the  UMath  class, and I approved this message."
         );
      }



   /*:                                    :METHOD:037:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   This method allows this class file to be unit tested as a standalone application. It's the method
   that's called when the class is invoked from the command line by using the java application launcher
   - "java". Main() is not a required method, but the practice of putting one in each class and
   wrapping class test code within it allows easy unit testing of the class; and main does not need to
   be removed when testing is complete.

   <P>
      <DL>
         <DT>
            <B>
               Command line usage:
            </B>
            <DD>
               Java cosmicabyss.com.lib.UMath
            </DD>
         </DT>
      </DL>

   <P><B>Implementation: </B><A HREF="UMath.java.html#037">View source</A>

   @param
      pArgs contains the command line arguments with which this class was invoked as an application.
   *//*
   ---------------------------------------------------------------------------------------------------- */
   public static void main(String[] pArgs) throws Exception
      {
      /*.
      ==========================================================================================
      Test code
      ------------------------------------------------------------------------------------------ */
      System.out.println("min(1,2,5,-2,37.5,-5.9,33456)=" + min(1,2,5,-2,37.5,-5.9,33456));
      System.out.println("lcm(50, 100, 127, 128, 359, 360, 240, 255, 1000, 10000)=" + lcm(50, 100, 127, 128, 359, 360, 240, 255, 1000, 10000));
      System.out.println("lcm(127, 128)=" + lcm(127, 128));
      System.out.println("gcd(-256, 128)=" + gcd(-256, 128));
      System.out.println("gcd(-256, 128, 512)=" + gcd(-256, 128, 512));
      }



   }  // class UMath



   /*:                                    :METHOD:038:BOOKMARK:
   ====================================================================================================
   [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
   ==================================================================================================== *//**
   See "Comparing floating point numbers" by Bruce Dawson, at
   http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

   Warning: Needs to be converted from C to Java.

   <P><B>Implementation: </B><A HREF="UMath.java.html#038">View source</A>

   *//*
   ---------------------------------------------------------------------------------------------------- */
//   bool AlmostEqual2sComplement(float A, float B, int maxUlps)
//      {
//      // Make sure maxUlps is non-negative and small enough that the
//      // default NAN won't compare as equal to anything.
//      assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
//      int aInt = *(int*)&A;
//      // Make aInt lexicographically ordered as a twos-complement int
//      if (aInt < 0) aInt = 0x80000000 - aInt;
//      // Make bInt lexicographically ordered as a twos-complement int
//      int bInt = *(int*)&B;
//      if (bInt < 0) bInt = 0x80000000 - bInt;
//      int intDiff = abs(aInt - bInt);
//      if (intDiff <= maxUlps) return true;
//      return false;
//      }


   /*:.
   ==============================================================================================================
   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[  Notes  ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   ============================================================================================================== */