All Downloads are FREE. Search and download functionalities are using the official Maven repository.

umcg.genetica.math.Fmath Maven / Gradle / Ivy

There is a newer version: 1.0.7
Show newest version
/*
*   Class   Fmath
*
*   USAGE:  Mathematical class that supplements java.lang.Math and contains:
*               the main physical constants
*               trigonemetric functions absent from java.lang.Math
*               some useful additional mathematical functions
*               some conversion functions
*
*   WRITTEN BY: Dr Michael Thomas Flanagan
*
*   DATE:    June 2002
*   AMENDED: 6 January 2006, 12 April 2006, 5 May 2006, 28 July 2006, 27 December 2006,
*            29 March 2007, 29 April 2007, 2,9,15 & 26 June 2007, 20 October 2007, 4-6 December 2007
*            27 February 2008, 25 April 2008, 26 April 2008, 13 May 2008, 25/26 May 2008, 3-7 July 2008
*            11 November 2010, 9-18 January 2011, 13 August 2011
*
*   DOCUMENTATION:
*   See Michael Thomas Flanagan's Java library on-line web pages:
*   http://www.ee.ucl.ac.uk/~mflanaga/java/
*   http://www.ee.ucl.ac.uk/~mflanaga/java/Fmath.html
*
*   Copyright (c) 2002 - 2011
*
*   PERMISSION TO COPY:
*   Permission to use, copy and modify this software and its documentation for
*   NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement
*   to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies.
*
*   Dr Michael Thomas Flanagan makes no representations about the suitability
*   or fitness of the software for any or for a particular purpose.
*   Michael Thomas Flanagan shall not be liable for any damages suffered
*   as a result of using, modifying or distributing this software or its derivatives.
*
***************************************************************************************/

package umcg.genetica.math;


import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

public class Fmath{

        // PHYSICAL CONSTANTS

        public static final double N_AVAGADRO = 6.0221419947e23;        /*      mol^-1          */
        public static final double K_BOLTZMANN = 1.380650324e-23;       /*      J K^-1          */
        public static final double H_PLANCK = 6.6260687652e-34;         /*      J s             */
        public static final double H_PLANCK_RED = H_PLANCK/(2*Math.PI); /*      J s             */
        public static final double C_LIGHT = 2.99792458e8;              /*      m s^-1          */
        public static final double R_GAS = 8.31447215;                  /*      J K^-1 mol^-1   */
        public static final double F_FARADAY = 9.6485341539e4;          /*      C mol^-1        */
        public static final double T_ABS = -273.15;                     /*      Celsius         */
        public static final double Q_ELECTRON = -1.60217646263e-19;     /*      C               */
        public static final double M_ELECTRON = 9.1093818872e-31;       /*      kg              */
        public static final double M_PROTON = 1.6726215813e-27;         /*      kg              */
        public static final double M_NEUTRON = 1.6749271613e-27;        /*      kg              */
        public static final double EPSILON_0 = 8.854187817e-12;         /*      F m^-1          */
        public static final double MU_0 = Math.PI*4e-7;                 /*      H m^-1 (N A^-2) */
        public static final double ETA_0 = MU_0*C_LIGHT;                /*      Ohms            */


        // MATHEMATICAL CONSTANTS
        public static final double EULER_CONSTANT_GAMMA = 0.5772156649015627;
        public static final double PI = Math.PI;                        /*  3.141592653589793D  */
        public static final double E = Math.E;                          /*  2.718281828459045D  */

        // HashMap for 'arithmetic integer' recognition nmethod
        private static final Map integers = new HashMap();
        static{
            integers.put(Integer.class, BigDecimal.valueOf(Integer.MAX_VALUE));
            integers.put(Long.class, BigDecimal.valueOf(Long.MAX_VALUE));
            integers.put(Byte.class, BigDecimal.valueOf(Byte.MAX_VALUE));
            integers.put(Short.class, BigDecimal.valueOf(Short.MAX_VALUE));
            integers.put(BigInteger.class, BigDecimal.valueOf(-1));
        }

        // METHODS

        // LOGARITHMS
        // Log to base 10 of a double number
        public static double log10(double a){
            return Math.log(a)/Math.log(10.0D);
        }

        // Log to base 10 of a float number
        public static float log10(float a){
            return (float) (Math.log((double)a)/Math.log(10.0D));
        }

        // Base 10 antilog of a double
        public static double antilog10(double x){
            return Math.pow(10.0D, x);
        }

        // Base 10 antilog of a float
        public static float antilog10(float x){
            return (float)Math.pow(10.0D, (double)x);
        }

        // Log to base e of a double number
        public static double log(double a){
            return Math.log(a);
        }

        // Log to base e of a float number
        public static float log(float a){
            return (float)Math.log((double)a);
        }

        // Base e antilog of a double
        public static double antilog(double x){
            return Math.exp(x);
        }

        // Base e antilog of a float
        public static float antilog(float x){
            return (float)Math.exp((double)x);
        }

        // Log to base 2 of a double number
        public static double log2(double a){
            return Math.log(a)/Math.log(2.0D);
        }

        // Log to base 2 of a float number
        public static float log2(float a){
            return (float) (Math.log((double)a)/Math.log(2.0D));
        }

        // Base 2 antilog of a double
        public static double antilog2(double x){
            return Math.pow(2.0D, x);
        }

        // Base 2 antilog of a float
        public static float antilog2(float x){
            return (float)Math.pow(2.0D, (double)x);
        }

        // Log to base b of a double number and double base
        public static double log10(double a, double b){
            return Math.log(a)/Math.log(b);
        }

        // Log to base b of a double number and int base
        public static double log10(double a, int b){
            return Math.log(a)/Math.log((double)b);
        }

        // Log to base b of a float number and flaot base
        public static float log10(float a, float b){
            return (float) (Math.log((double)a)/Math.log((double)b));
        }

        // Log to base b of a float number and int base
        public static float log10(float a, int b){
            return (float) (Math.log((double)a)/Math.log((double)b));
        }

        // SQUARES
        // Square of a double number
        public static double square(double a){
            return a*a;
        }

        // Square of a float number
        public static float square(float a){
            return a*a;
        }

        // Square of a BigDecimal number
        public static BigDecimal square(BigDecimal a){
            return a.multiply(a);
        }

        // Square of an int number
        public static int square(int a){
            return a*a;
        }

        // Square of a long number
        public static long square(long a){
            return a*a;
        }

        // Square of a BigInteger number
        public static BigInteger square(BigInteger a){
            return a.multiply(a);
        }

        // FACTORIALS
        // factorial of n
        // argument and return are integer, therefore limited to 0<=n<=12
        // see below for long and double arguments
        public static int factorial(int n){
            if(n<0)throw new IllegalArgumentException("n must be a positive integer");
            if(n>12)throw new IllegalArgumentException("n must less than 13 to avoid integer overflow\nTry long or double argument");
            int f = 1;
            for(int i=2; i<=n; i++)f*=i;
            return f;
        }

        // factorial of n
        // argument and return are long, therefore limited to 0<=n<=20
        // see below for double argument
        public static long factorial(long n){
            if(n<0)throw new IllegalArgumentException("n must be a positive integer");
            if(n>20)throw new IllegalArgumentException("n must less than 21 to avoid long integer overflow\nTry double argument");
            long f = 1;
            long iCount = 2L;
            while(iCount<=n){
                f*=iCount;
                iCount += 1L;
            }
            return f;
        }

        // factorial of n
        // Argument is of type BigInteger
        public static BigInteger factorial(BigInteger n){
            if(n.compareTo(BigInteger.ZERO)==-1)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            BigInteger one = BigInteger.ONE;
            BigInteger f = one;
            BigInteger iCount = new BigInteger("2");
            while(iCount.compareTo(n)!=1){
                f = f.multiply(iCount);
                iCount = iCount.add(one);
            }
            one = null;
            iCount = null;
            return f;
        }

        // factorial of n
        // Argument is of type double but must be, numerically, an integer
        // factorial returned as double but is, numerically, should be an integer
        // numerical rounding may makes this an approximation after n = 21
        public static double factorial(double n){
            if(n<0.0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            double f = 1.0D;
            double iCount = 2.0D;
            while(iCount<=n){
                f*=iCount;
                iCount += 1.0D;
            }
            return f;
        }

        // factorial of n
        // Argument is of type BigDecimal but must be, numerically, an integer
        public static BigDecimal factorial(BigDecimal n){
            if(n.compareTo(BigDecimal.ZERO)==-1 || !Fmath.isInteger(n))throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            BigDecimal one = BigDecimal.ONE;
            BigDecimal f = one;
            BigDecimal iCount = new BigDecimal(2.0D);
            while(iCount.compareTo(n)!=1){
                f = f.multiply(iCount);
                iCount = iCount.add(one);
            }
            one = null;
            iCount = null;
            return f;
        }



        // log to base e of the factorial of n
        // log[e](factorial) returned as double
        // numerical rounding may makes this an approximation
        public static double logFactorial(int n){
            if(n<0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            double f = 0.0D;
            for(int i=2; i<=n; i++)f+=Math.log(i);
            return f;
        }

        // log to base e of the factorial of n
        // Argument is of type double but must be, numerically, an integer
        // log[e](factorial) returned as double
        // numerical rounding may makes this an approximation
        public static double logFactorial(long n){
            if(n<0L)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            double f = 0.0D;
            long iCount = 2L;
            while(iCount<=n){
                f+=Math.log(iCount);
                iCount += 1L;
            }
            return f;
        }

        // log to base e of the factorial of n
        // Argument is of type double but must be, numerically, an integer
        // log[e](factorial) returned as double
        // numerical rounding may makes this an approximation
        public static double logFactorial(double n){
            if(n<0 || (n-Math.floor(n))!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
            double f = 0.0D;
            double iCount = 2.0D;
            while(iCount<=n){
                f+=Math.log(iCount);
                iCount += 1.0D;
            }
            return f;
        }


        // SIGN
        /*      returns -1 if x < 0 else returns 1   */
        //  double version
        public static double sign(double x){
            if (x<0.0){
                return -1.0;
            }
            else{
                return 1.0;
            }
        }

        /*      returns -1 if x < 0 else returns 1   */
        //  float version
        public static float sign(float x){
            if (x<0.0F){
                return -1.0F;
            }
            else{
                return 1.0F;
            }
        }

        /*      returns -1 if x < 0 else returns 1   */
        //  int version
        public static int sign(int x){
            if (x<0){
                return -1;
            }
            else{
                return 1;
            }
        }

        /*      returns -1 if x < 0 else returns 1   */
        // long version
        public static long sign(long x){
            if (x<0){
                return -1;
            }
            else{
                return 1;
            }
        }

        // ADDITIONAL TRIGONOMETRIC FUNCTIONS

        // Returns the length of the hypotenuse of a and b
        // i.e. sqrt(a*a+b*b) [without unecessary overflow or underflow]
        // double version
        public static double hypot(double aa, double bb){
            double amod=Math.abs(aa);
            double bmod=Math.abs(bb);
            double cc = 0.0D, ratio = 0.0D;
            if(amod==0.0){
                cc=bmod;
            }
            else{
                if(bmod==0.0){
                    cc=amod;
                }
                else{
                    if(amod>=bmod){
                        ratio=bmod/amod;
                        cc=amod*Math.sqrt(1.0 + ratio*ratio);
                    }
                    else{
                        ratio=amod/bmod;
                        cc=bmod*Math.sqrt(1.0 + ratio*ratio);
                    }
                }
            }
            return cc;
        }

        // Returns the length of the hypotenuse of a and b
        // i.e. sqrt(a*a+b*b) [without unecessary overflow or underflow]
        // float version
        public static float hypot(float aa, float bb){
            return (float) hypot((double) aa, (double) bb);
        }

        // Angle (in radians) subtended at coordinate C
        // given x, y coordinates of all apices, A, B and C, of a triangle
        public static double angle(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){

            double ccos = Fmath.cos(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC);
            return Math.acos(ccos);
        }

        // Angle (in radians) between sides sideA and sideB given all side lengths of a triangle
        public static double angle(double sideAC, double sideBC, double sideAB){

            double ccos = Fmath.cos(sideAC, sideBC, sideAB);
            return Math.acos(ccos);
        }

        // Sine of angle subtended at coordinate C
        // given x, y coordinates of all apices, A, B and C, of a triangle
        public static double sin(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){
            double angle = Fmath.angle(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC);
            return Math.sin(angle);
        }

        // Sine of angle between sides sideA and sideB given all side lengths of a triangle
        public static double sin(double sideAC, double sideBC, double sideAB){
            double angle = Fmath.angle(sideAC, sideBC, sideAB);
            return Math.sin(angle);
        }

        // Sine given angle in radians
        // for completion - returns Math.sin(arg)
        public static double sin(double arg){
            return Math.sin(arg);
        }

        // Inverse sine
        // Fmath.asin Checks limits - Java Math.asin returns NaN if without limits
        public static double asin(double a){
            if(a<-1.0D && a>1.0D) throw new IllegalArgumentException("Fmath.asin argument (" + a + ") must be >= -1.0 and <= 1.0");
            return Math.asin(a);
        }

        // Cosine of angle subtended at coordinate C
        // given x, y coordinates of all apices, A, B and C, of a triangle
        public static double cos(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){
            double sideAC = Fmath.hypot(xAtA - xAtC, yAtA - yAtC);
            double sideBC = Fmath.hypot(xAtB - xAtC, yAtB - yAtC);
            double sideAB = Fmath.hypot(xAtA - xAtB, yAtA - yAtB);
            return Fmath.cos(sideAC, sideBC, sideAB);
        }

        // Cosine of angle between sides sideA and sideB given all side lengths of a triangle
        public static double cos(double sideAC, double sideBC, double sideAB){
            return 0.5D*(sideAC/sideBC + sideBC/sideAC - (sideAB/sideAC)*(sideAB/sideBC));
        }

         // Cosine given angle in radians
         // for completion - returns Java Math.cos(arg)
        public static double cos(double arg){
            return Math.cos(arg);
        }

        // Inverse cosine
        // Fmath.asin Checks limits - Java Math.asin returns NaN if without limits
        public static double acos(double a){
            if(a<-1.0D || a>1.0D) throw new IllegalArgumentException("Fmath.acos argument (" + a + ") must be >= -1.0 and <= 1.0");
            return Math.acos(a);
        }

        // Tangent of angle subtended at coordinate C
        // given x, y coordinates of all apices, A, B and C, of a triangle
        public static double tan(double xAtA, double yAtA, double xAtB, double yAtB, double xAtC, double yAtC){
            double angle = Fmath.angle(xAtA, yAtA, xAtB, yAtB, xAtC, yAtC);
            return Math.tan(angle);
        }

        // Tangent of angle between sides sideA and sideB given all side lengths of a triangle
        public static double tan(double sideAC, double sideBC, double sideAB){
            double angle = Fmath.angle(sideAC, sideBC, sideAB);
            return Math.tan(angle);
        }

        // Tangent given angle in radians
        // for completion - returns Math.tan(arg)
        public static double tan(double arg){
            return Math.tan(arg);
        }

        // Inverse tangent
        // for completion - returns Math.atan(arg)
        public static double atan(double a){
            return Math.atan(a);
        }

        // Inverse tangent - ratio numerator and denominator provided
        // for completion - returns Math.atan2(arg)
        public static double atan2(double a, double b){
            return Math.atan2(a, b);
        }

        // Cotangent
        public static double cot(double a){
            return 1.0D/Math.tan(a);
        }

        // Inverse cotangent
        public static double acot(double a){
            return Math.atan(1.0D/a);
        }

        // Inverse cotangent - ratio numerator and denominator provided
        public static double acot2(double a, double b){
            return Math.atan2(b, a);
        }

        // Secant
        public static double sec(double a){
            return 1.0/Math.cos(a);
        }

        // Inverse secant
        public static double asec(double a){
            if(a<1.0D && a>-1.0D) throw new IllegalArgumentException("asec argument (" + a + ") must be >= 1 or <= -1");
            return Math.acos(1.0/a);
        }

        // Cosecant
        public static double csc(double a){
            return 1.0D/Math.sin(a);
        }

        // Inverse cosecant
        public static double acsc(double a){
            if(a<1.0D && a>-1.0D) throw new IllegalArgumentException("acsc argument (" + a + ") must be >= 1 or <= -1");
            return Math.asin(1.0/a);
        }

        // Exsecant
        public static double exsec(double a){
            return (1.0/Math.cos(a)-1.0D);
        }

        // Inverse exsecant
        public static double aexsec(double a){
            if(a<0.0D && a>-2.0D) throw new IllegalArgumentException("aexsec argument (" + a + ") must be >= 0.0 and <= -2");
            return Math.asin(1.0D/(1.0D + a));
        }

        // Versine
        public static double vers(double a){
            return (1.0D - Math.cos(a));
        }

        // Inverse  versine
        public static double avers(double a){
            if(a<0.0D && a>2.0D) throw new IllegalArgumentException("avers argument (" + a + ") must be <= 2 and >= 0");
            return Math.acos(1.0D - a);
        }

        // Coversine
        public static double covers(double a){
            return (1.0D - Math.sin(a));
        }

        // Inverse coversine
        public static double acovers(double a){
            if(a<0.0D && a>2.0D) throw new IllegalArgumentException("acovers argument (" + a + ") must be <= 2 and >= 0");
            return Math.asin(1.0D - a);
        }

        // Haversine
        public static double hav(double a){
            return 0.5D*Fmath.vers(a);
        }

        // Inverse haversine
        public static double ahav(double a){
            if(a<0.0D && a>1.0D) throw new IllegalArgumentException("ahav argument (" + a + ") must be >= 0 and <= 1");
            return Fmath.acos(1.0D - 2.0D*a);
        }

        // Unnormalised sinc (unnormalised sine cardinal)   sin(x)/x
        public static double sinc(double a){
            if(Math.abs(a)<1e-40){
                return 1.0D;
            }
            else{
                return Math.sin(a)/a;
            }
        }

        // Normalised sinc (normalised sine cardinal)  sin(pi.x)/(pi.x)
        public static double nsinc(double a){
            if(Math.abs(a)<1e-40){
                return 1.0D;
            }
            else{
                return Math.sin(Math.PI*a)/(Math.PI*a);
            }
        }

        //Hyperbolic sine of a double number
        public static double sinh(double a){
            return 0.5D*(Math.exp(a)-Math.exp(-a));
        }

        // Inverse hyperbolic sine of a double number
        public static double asinh(double a){
            double sgn = 1.0D;
            if(a<0.0D){
                sgn = -1.0D;
                a = -a;
            }
            return sgn*Math.log(a+Math.sqrt(a*a+1.0D));
        }

        //Hyperbolic cosine of a double number
        public static double cosh(double a){
            return 0.5D*(Math.exp(a)+Math.exp(-a));
        }

        // Inverse hyperbolic cosine of a double number
        public static double acosh(double a){
            if(a<1.0D) throw new IllegalArgumentException("acosh real number argument (" + a + ") must be >= 1");
            return Math.log(a+Math.sqrt(a*a-1.0D));
        }

        //Hyperbolic tangent of a double number
        public static double tanh(double a){
            return sinh(a)/cosh(a);
        }

        // Inverse hyperbolic tangent of a double number
        public static double atanh(double a){
            double sgn = 1.0D;
            if(a<0.0D){
                sgn = -1.0D;
                a = -a;
            }
            if(a>1.0D) throw new IllegalArgumentException("atanh real number argument (" + sgn*a + ") must be >= -1 and <= 1");
            return 0.5D*sgn*(Math.log(1.0D + a)-Math.log(1.0D - a));
        }

        //Hyperbolic cotangent of a double number
        public static double coth(double a){
            return 1.0D/tanh(a);
        }

        // Inverse hyperbolic cotangent of a double number
        public static double acoth(double a){
            double sgn = 1.0D;
            if(a<0.0D){
                sgn = -1.0D;
                a = -a;
            }
            if(a<1.0D) throw new IllegalArgumentException("acoth real number argument (" + sgn*a + ") must be <= -1 or >= 1");
            return 0.5D*sgn*(Math.log(1.0D + a)-Math.log(a - 1.0D));
        }

        //Hyperbolic secant of a double number
        public static double sech(double a){
                return 1.0D/cosh(a);
        }

        // Inverse hyperbolic secant of a double number
        public static double asech(double a){
            if(a>1.0D || a<0.0D) throw new IllegalArgumentException("asech real number argument (" + a + ") must be >= 0 and <= 1");
            return 0.5D*(Math.log(1.0D/a + Math.sqrt(1.0D/(a*a) - 1.0D)));
        }

        //Hyperbolic cosecant of a double number
        public static double csch(double a){
                return 1.0D/sinh(a);
        }

        // Inverse hyperbolic cosecant of a double number
        public static double acsch(double a){
            double sgn = 1.0D;
            if(a<0.0D){
                sgn = -1.0D;
                a = -a;
            }
            return 0.5D*sgn*(Math.log(1.0/a + Math.sqrt(1.0D/(a*a) + 1.0D)));
        }

    // DETERMINING PRECISION i.e. number of mantissa places
    public static int checkPrecision(double number){
        boolean test = true;
        int prec = 0;
        if(Fmath.isNaN(number))test=false;
        if(Fmath.isPlusInfinity(number))test=false;
        if(Fmath.isMinusInfinity(number))test=false;
        while(test){
            if(number==Fmath.truncate(number, prec)){
                test = false;
            }
            else{
                prec++;
                if(prec>20)test=false;
            }
        }
        return prec;
    }

    public static int checkPrecision(float number){
        return checkPrecision((double)number);
    }


    // MANTISSA ROUNDING (TRUNCATING)
    // returns a value of xDouble truncated to trunc decimal places
    public static double truncate(double xDouble, int trunc){
        double xTruncated = xDouble;
        if(!Fmath.isNaN(xDouble)){
            if(!Fmath.isPlusInfinity(xDouble)){
                if(!Fmath.isMinusInfinity(xDouble)){
                    if(xDouble!=0.0D){
                        String xString = ((new Double(xDouble)).toString()).trim();
                        xTruncated = Double.parseDouble(truncateProcedure(xString, trunc));
                    }
                }
            }
        }
        return xTruncated;
    }

    // returns a value of xFloat truncated to trunc decimal places
    public static float truncate(float xFloat, int trunc){
        float xTruncated = xFloat;
        if(!Fmath.isNaN(xFloat)){
            if(!Fmath.isPlusInfinity(xFloat)){
                if(!Fmath.isMinusInfinity(xFloat)){
                    if(xFloat!=0.0D){
                        String xString = ((new Float(xFloat)).toString()).trim();
                        xTruncated = Float.parseFloat(truncateProcedure(xString, trunc));
                    }
                }
            }
        }
        return xTruncated;
    }

    // private method for truncating a float or double expressed as a String
    private static String truncateProcedure(String xValue, int trunc){

        String xTruncated = xValue;
        String xWorking = xValue;
        String exponent = " ";
        String first = "+";
        int expPos = xValue.indexOf('E');
        int dotPos = xValue.indexOf('.');
        int minPos = xValue.indexOf('-');

        if(minPos!=-1){
            if(minPos==0){
                xWorking = xWorking.substring(1);
                first = "-";
                dotPos--;
                expPos--;
            }
        }
        if(expPos>-1){
            exponent = xWorking.substring(expPos);
            xWorking = xWorking.substring(0,expPos);
        }
        String xPreDot = null;
        String xPostDot = "0";
        String xDiscarded = null;
        String tempString = null;
        double tempDouble = 0.0D;
        if(dotPos>-1){
            xPreDot = xWorking.substring(0,dotPos);
            xPostDot = xWorking.substring(dotPos+1);
            int xLength = xPostDot.length();
            if(trunc1){
                    tempString += xDiscarded.substring(1);
                }
                else{
                    tempString += "0";
                }
                tempDouble = Math.round(Double.parseDouble(tempString));

                if(trunc>0){
                    if(tempDouble>=5.0){
                        int[] xArray = new int[trunc+1];
                        xArray[0] = 0;
                        for(int i=0; i0){
                                if(xArray[iCounter]<10){
                                    test = false;
                                }
                                else{
                                    xArray[iCounter]=0;
                                    iCounter--;
                                }
                            }
                            else{
                                test = false;
                            }
                        }
                        int preInt = Integer.parseInt(xPreDot);
                        preInt += xArray[0];
                        xPreDot = (new Integer(preInt)).toString();
                        tempString = "";
                        for(int i=1; i<=trunc; i++){
                            tempString += (new Integer(xArray[i])).toString();
                        }
                        xPostDot = tempString;
                    }
                    else{
                        xPostDot = xPostDot.substring(0, trunc);
                    }
                }
                else{
                    if(tempDouble>=5.0){
                        int preInt = Integer.parseInt(xPreDot);
                        preInt++;
                        xPreDot = (new Integer(preInt)).toString();
                    }
                    xPostDot = "0";
                }
            }
            xTruncated = first + xPreDot.trim() + "." + xPostDot.trim() + exponent;
        }
        return xTruncated.trim();
    }

        // Returns true if x is infinite, i.e. is equal to either plus or minus infinity
        // x is double
        public static boolean isInfinity(double x){
            boolean test=false;
            if(x==Double.POSITIVE_INFINITY || x==Double.NEGATIVE_INFINITY)test=true;
            return test;
        }

        // Returns true if x is infinite, i.e. is equal to either plus or minus infinity
        // x is float
        public static boolean isInfinity(float x){
            boolean test=false;
            if(x==Float.POSITIVE_INFINITY || x==Float.NEGATIVE_INFINITY)test=true;
            return test;
        }

        // Returns true if x is plus infinity
        // x is double
        public static boolean isPlusInfinity(double x){
            boolean test=false;
            if(x==Double.POSITIVE_INFINITY)test=true;
            return test;
        }

        // Returns true if x is plus infinity
        // x is float
        public static boolean isPlusInfinity(float x){
            boolean test=false;
            if(x==Float.POSITIVE_INFINITY)test=true;
            return test;
        }

        // Returns true if x is minus infinity
        // x is double
        public static boolean isMinusInfinity(double x){
            boolean test=false;
            if(x==Double.NEGATIVE_INFINITY)test=true;
            return test;
        }

        // Returns true if x is minus infinity
        // x is float
        public static boolean isMinusInfinity(float x){
            boolean test=false;
            if(x==Float.NEGATIVE_INFINITY)test=true;
            return test;
        }


        // Returns true if x is 'Not a Number' (NaN)
        // x is double
        public static boolean isNaN(double x){
            boolean test=false;
            if(x!=x)test=true;
            return test;
        }

        // Returns true if x is 'Not a Number' (NaN)
        // x is float
        public static boolean isNaN(float x){
            boolean test=false;
            if(x!=x)test=true;
            return test;
        }

        // Returns true if x equals y
        // x and y are double
        // x may be float within range, PLUS_INFINITY, NEGATIVE_INFINITY, or NaN
        // NB!! This method treats two NaNs as equal
        public static boolean isEqual(double x, double y){
            boolean test=false;
            if(Fmath.isNaN(x)){
                if(Fmath.isNaN(y))test=true;
            }
            else{
                if(Fmath.isPlusInfinity(x)){
                    if(Fmath.isPlusInfinity(y))test=true;
                }
                else{
                    if(Fmath.isMinusInfinity(x)){
                        if(Fmath.isMinusInfinity(y))test=true;
                    }
                    else{
                        if(x==y)test=true;
                    }
                }
            }
            return test;
        }

        // Returns true if x equals y
        // x and y are float
        // x may be float within range, PLUS_INFINITY, NEGATIVE_INFINITY, or NaN
        // NB!! This method treats two NaNs as equal
        public static boolean isEqual(float x, float y){
            boolean test=false;
            if(Fmath.isNaN(x)){
                if(Fmath.isNaN(y))test=true;
            }
            else{
                if(Fmath.isPlusInfinity(x)){
                    if(Fmath.isPlusInfinity(y))test=true;
                }
                else{
                    if(Fmath.isMinusInfinity(x)){
                        if(Fmath.isMinusInfinity(y))test=true;
                    }
                    else{
                        if(x==y)test=true;
                    }
                }
            }
            return test;
        }

        // Returns true if x equals y
        // x and y are int
        public static boolean isEqual(int x, int y){
            boolean test=false;
            if(x==y)test=true;
            return test;
        }

        // Returns true if x equals y
        // x and y are char
        public static boolean isEqual(char x, char y){
            boolean test=false;
            if(x==y)test=true;
            return test;
        }

        // Returns true if x equals y
        // x and y are Strings
        public static boolean isEqual(String x, String y){
            boolean test=false;
            if(x.equals(y))test=true;
            return test;
        }

        // IS EQUAL WITHIN LIMITS
        // Returns true if x equals y within limits plus or minus limit
        // x and y are double
        public static boolean isEqualWithinLimits(double x, double y, double limit){
            boolean test=false;
            if(Math.abs(x-y)<=Math.abs(limit))test=true;
            return test;
        }

        // Returns true if x equals y within limits plus or minus limit
        // x and y are float
        public static boolean isEqualWithinLimits(float x, float y, float limit){
            boolean test=false;
            if(Math.abs(x-y)<=Math.abs(limit))test=true;
            return test;
        }

        // Returns true if x equals y within limits plus or minus limit
        // x and y are long
        public static boolean isEqualWithinLimits(long x, long y, long limit){
            boolean test=false;
            if(Math.abs(x-y)<=Math.abs(limit))test=true;
            return test;
        }

        // Returns true if x equals y within limits plus or minus limit
        // x and y are int
        public static boolean isEqualWithinLimits(int x, int y, int limit){
            boolean test=false;
            if(Math.abs(x-y)<=Math.abs(limit))test=true;
            return test;
        }

        // Returns true if x equals y within limits plus or minus limit
        // x and y are BigDecimal
        public static boolean isEqualWithinLimits(BigDecimal x, BigDecimal y, BigDecimal limit){
            boolean test=false;
            if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true;
            return test;
        }

        // Returns true if x equals y within limits plus or minus limit
        // x and y are BigInteger
        public static boolean isEqualWithinLimits(BigInteger x, BigInteger y, BigInteger limit){
            boolean test=false;
            if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true;
            return test;
        }


        // IS EQUAL WITHIN A PERCENTAGE
        // Returns true if x equals y within a percentage of the mean
        // x and y are double
        public static boolean isEqualWithinPerCent(double x, double y, double perCent){
            boolean test=false;
            double limit = Math.abs((x+y)*perCent/200.0D);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are float
        public static boolean isEqualWithinPerCent(float x, float y, float perCent){
            boolean test=false;
            double limit = Math.abs((x+y)*perCent/200.0F);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are long, percentage provided as double
        public static boolean isEqualWithinPerCent(long x, long y, double perCent){
            boolean test=false;
            double limit = Math.abs((x+y)*perCent/200.0D);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are long, percentage provided as int
        public static boolean isEqualWithinPerCent(long x, long y, long perCent){
            boolean test=false;
            double limit = Math.abs((double)(x+y)*(double)perCent/200.0D);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are int, percentage provided as double
        public static boolean isEqualWithinPerCent(int x, int y, double perCent){
            boolean test=false;
            double limit = Math.abs((double)(x+y)*perCent/200.0D);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are int, percentage provided as int
        public static boolean isEqualWithinPerCent(int x, int y, int perCent){
            boolean test=false;
            double limit = Math.abs((double)(x+y)*(double)perCent/200.0D);
            if(Math.abs(x-y)<=limit)test=true;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are BigDecimal
        public static boolean isEqualWithinPerCent(BigDecimal x, BigDecimal y, BigDecimal perCent){
            boolean test=false;
            BigDecimal limit = (x.add(y)).multiply(perCent).multiply(new BigDecimal("0.005"));
            if(((x.subtract(y)).abs()).compareTo(limit.abs())<=0)test = true;
            limit = null;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are BigDInteger, percentage provided as BigDecimal
        public static boolean isEqualWithinPerCent(BigInteger x, BigInteger y, BigDecimal perCent){
            boolean test=false;
            BigDecimal xx = new BigDecimal(x);
            BigDecimal yy = new BigDecimal(y);
            BigDecimal limit = (xx.add(yy)).multiply(perCent).multiply(new BigDecimal("0.005"));
            if(((xx.subtract(yy)).abs()).compareTo(limit.abs())<=0)test = true;
            limit = null;
            xx = null;
            yy = null;
            return test;
        }

        // Returns true if x equals y within a percentage of the mean
        // x and y are BigDInteger, percentage provided as BigInteger
        public static boolean isEqualWithinPerCent(BigInteger x, BigInteger y, BigInteger perCent){
            boolean test=false;
            BigDecimal xx = new BigDecimal(x);
            BigDecimal yy = new BigDecimal(y);
            BigDecimal pc = new BigDecimal(perCent);
            BigDecimal limit = (xx.add(yy)).multiply(pc).multiply(new BigDecimal("0.005"));
            if(((xx.subtract(yy)).abs()).compareTo(limit.abs())<=0)test = true;
            limit = null;
            xx = null;
            yy = null;
            pc = null;
            return test;
        }

        // COMPARISONS
        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are double
        public static int compare(double x, double y){
            Double X = new Double(x);
            Double Y = new Double(y);
            return X.compareTo(Y);
        }

        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are int
        public static int compare(int x, int y){
            Integer X = new Integer(x);
            Integer Y = new Integer(y);
            return X.compareTo(Y);
        }

        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are long
        public static int compare(long x, long y){
            Long X = new Long(x);
            Long Y = new Long(y);
            return X.compareTo(Y);
        }

        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are float
        public static int compare(float x, float y){
            Float X = new Float(x);
            Float Y = new Float(y);
            return X.compareTo(Y);
        }

        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are short
        public static int compare(byte x, byte y){
            Byte X = new Byte(x);
            Byte Y = new Byte(y);
            return X.compareTo(Y);
        }

        // Returns 0 if x == y
        // Returns -1 if x < y
        // Returns 1 if x > y
        // x and y are short
        public static int compare(short x, short y){
            Short X = new Short(x);
            Short Y = new Short(y);
            return X.compareTo(Y);
        }

        // COMPARE ARRAYS
        // Returns true if arrays identical, false if not
        // arrays - double[]
        public static boolean compare(double[] array1, double[] array2){
            boolean ret = true;
            int n = array1.length;
            int m = array2.length;
            if(n!=m){
                ret = false;
            }
            else{
                for(int i=0; i=1970){
                yearDiff += 365;
                if(Fmath.leapYear(yearTest))yearDiff++;
                yearTest--;
            }
            yearDiff *= 24L*60L*60L*1000L;

            long monthDiff = 0L;
            int monthTest = month -1;
            while(monthTest>0){
                monthDiff += monthDays[monthTest];
                if(Fmath.leapYear(year))monthDiff++;
                monthTest--;
            }

            monthDiff *= 24L*60L*60L*1000L;

            ms = yearDiff + monthDiff + day*24L*60L*60L*1000L + hour*60L*60L*1000L + min*60L*1000L + sec*1000L;

            return ms;
        }

        // DEPRECATED METHODS
        // Several methods have been revised and moved to classes ArrayMaths, Conv or PrintToScreen

        // ARRAY MAXIMUM  (deprecated - see ArryMaths class)
        // Maximum of a 1D array of doubles, aa
        public static double maximum(double[] aa){
            int n = aa.length;
            double aamax=aa[0];
            for(int i=1; iaamax)aamax=aa[i];
            }
            return aamax;
        }

        // Maximum of a 1D array of floats, aa
        public static float maximum(float[] aa){
            int n = aa.length;
            float aamax=aa[0];
            for(int i=1; iaamax)aamax=aa[i];
            }
            return aamax;
        }

        // Maximum of a 1D array of ints, aa
        public static int maximum(int[] aa){
            int n = aa.length;
            int aamax=aa[0];
            for(int i=1; iaamax)aamax=aa[i];
            }
            return aamax;
        }

        // Maximum of a 1D array of longs, aa
        public static long maximum(long[] aa){
            long n = aa.length;
            long aamax=aa[0];
            for(int i=1; iaamax)aamax=aa[i];
            }
            return aamax;
        }

        // Minimum of a 1D array of doubles, aa
        public static double minimum(double[] aa){
            int n = aa.length;
            double aamin=aa[0];
            for(int i=1; i double[]
        public static double[] arrayMultByConstant(double[] aa, double constant){
            int n = aa.length;
            double[] bb = new double[n];
            for(int i=0; i double[]
        public static double[] arrayMultByConstant(int[] aa, double constant){
            int n = aa.length;
            double[] bb = new double[n];
            for(int i=0; i double[]
        public static double[] arrayMultByConstant(double[] aa, int constant){
            int n = aa.length;
            double[] bb = new double[n];
            for(int i=0; i double[]
        public static double[] arrayMultByConstant(int[] aa, int constant){
            int n = aa.length;
            double[] bb = new double[n];
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i arrayl = new ArrayList();
            for(int i=0; i=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of floats
        // returns -1 if none found
        public static int indexOf(float[] array, float value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of longs
        // returns -1 if none found
        public static int indexOf(long[] array, long value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of ints
        // returns -1 if none found
        public static int indexOf(int[] array, int value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of bytes
        // returns -1 if none found
        public static int indexOf(byte[] array, byte value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of shorts
        // returns -1 if none found
        public static int indexOf(short[] array, short value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of chars
        // returns -1 if none found
        public static int indexOf(char[] array, char value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter]==value){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of Strings
        // returns -1 if none found
        public static int indexOf(String[] array, String value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter].equals(value)){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // finds the index of the first occurence of the element equal to a given value in an array of Objects
        // returns -1 if none found
        public static int indexOf(Object[] array, Object value){
            int index = -1;
            boolean test = true;
            int counter = 0;
            while(test){
                if(array[counter].equals(value)){
                    index = counter;
                    test = false;
                }
                else{
                    counter++;
                    if(counter>=array.length)test = false;
                }
            }
            return index;
        }

        // FIND  VALUE OF AND FIND VALUE OF ARRAY ELEMENTS NEAREST TO A VALUE  (deprecated - see ArryMaths class)
        // finds the value of nearest element value in array to the argument value
        public static double nearestElementValue(double[] array, double value){
            double diff = Math.abs(array[0] - value);
            double nearest = array[0];
            for(int i=1; i=0.0D){
                    diff0 = value - array[ii];
                    nearest = array[ii];
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = min;
                        diff0 = min - value;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0.0D && diff1=0.0D){
                    diff0 = value - array[ii];
                    nearest = ii;
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = minI;
                        diff0 = min - value;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0.0D && diff1max)max = array[ii];
                if((array[ii] - value )>=0.0D){
                    diff0 = value - array[ii];
                    nearest = array[ii];
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = max;
                        diff0 = value - max;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0.0D && diff1max){
                    max = array[ii];
                    maxI = ii;
                }
                if((array[ii] - value )>=0.0D){
                    diff0 = value - array[ii];
                    nearest = ii;
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = maxI;
                        diff0 = value - max;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0.0D && diff1=0){
                    diff0 = value - array[ii];
                    nearest = array[ii];
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = min;
                        diff0 = min - value;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0 && diff1=0){
                    diff0 = value - array[ii];
                    nearest = ii;
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = minI;
                        diff0 = min - value;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0 && diff1max)max = array[ii];
                if((array[ii] - value )>=0){
                    diff0 = value - array[ii];
                    nearest = array[ii];
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = max;
                        diff0 = value - max;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0 && diff1max){
                    max = array[ii];
                    maxI = ii;
                }
                if((array[ii] - value )>=0){
                    diff0 = value - array[ii];
                    nearest = ii;
                    test = false;
                }
                else{
                    ii++;
                    if(ii>array.length-1){
                        nearest = maxI;
                        diff0 = value - max;
                        test = false;
                    }
                }
            }
            for(int i=0; i=0 && diff10)sum += i;
            return sum;
        }


        // PRODUCT OF ALL ELEMENTS  (deprecated - see ArryMaths class)
        // Product of all array elements - double array
        public static double arrayProduct(double[]array){
            double product = 1.0D;
            for(double i:array)product *= i;
            return product;
        }

        // Product of all array elements - float array
        public static float arrayProduct(float[]array){
            float product = 1.0F;
            for(float i:array)product *= i;
            return product;
        }

        // Product of all array elements - int array
        public static int arrayProduct(int[]array){
            int product = 1;
            for(int i:array)product *= i;
            return product;
        }

        // Product of all array elements - long array
        public static long arrayProduct(long[]array){
            long product = 1L;
            for(long i:array)product *= i;
            return product;
        }

        // CONCATENATE TWO ARRAYS  (deprecated - see ArryMaths class)
        // Concatenate two double arrays
        public static double[] concatenate(double[] aa, double[] bb){
            int aLen = aa.length;
            int bLen = bb.length;
            int cLen = aLen + bLen;
            double[] cc = new double[cLen];
            for(int i=0; i selectSortVector(double[] aa){
            ArrayList list = Fmath.selectSortArrayList(aa);
            Vector ret = null;
            if(list!=null){
                int n = list.size();
                ret = new Vector(n);
                for(int i=0; i selectSortArrayList(double[] aa){
            int index = 0;
            int lastIndex = -1;
            int n = aa.length;
            double holdb = 0.0D;
            int holdi = 0;
            double[] bb = new double[n];
            int[] indices = new int[n];
            for(int i=0; i arrayl = new ArrayList();
            arrayl.add(aa);
            arrayl.add(bb);
            arrayl.add(indices);
            return arrayl;
        }

        // sort elements in an array of doubles into ascending order
        // using selection sort method
        public static double[] selectionSort(double[] aa){
            int index = 0;
            int lastIndex = -1;
            int n = aa.length;
            double hold = 0.0D;
            double[] bb = new double[n];
            for(int i=0; i