org.netxilia.functions.MathFunctions.java Source code

Java tutorial

Introduction

Here is the source code for org.netxilia.functions.MathFunctions.java

Source

/*******************************************************************************
 * 
 * Copyright 2010 Alexandru Craciun, and individual contributors as indicated
 * by the @authors tag. 
 * 
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 ******************************************************************************/
package org.netxilia.functions;

import java.math.BigDecimal;
import java.util.Iterator;

import org.apache.commons.math.util.MathUtils;
import org.netxilia.spi.formula.Function;
import org.netxilia.spi.formula.Functions;

/**
 * This are the mathematical functions implemented by Google Docs
 */
@Functions
public class MathFunctions {

    public double ABS(double number) {
        return Math.abs(number);
    }

    public double ACOS(double number) {
        return Math.acos(number);
    }

    public double ACOSH(double x) {
        return Math.log(x + Math.sqrt(x * x - 1));
    }

    public double ASIN(double number) {
        return Math.asin(number);
    }

    public double ASINH(double x) {
        return Math.log(x + Math.sqrt(x * x + 1));
    }

    public double ATAN(double number) {
        return Math.atan(number);
    }

    public double ATAN2(double number_x, double number_y) {
        return Math.atan2(number_x, number_y);
    }

    public double ATANH(double x) {
        return Math.log((1 + x) / (1 - x)) / 2;
    }

    /**
     * Rounds the given number to the nearest integer or multiple of significance. Significance is the value to whose
     * multiple of ten the value is to be rounded up (.01, .1, 1, 10, etc.). Mode is an optional value. If it is
     * indicated and non-zero and if the number and significance are negative, rounding up is carried out based on that
     * value.
     * 
     * @return
     */
    public double CEILING(double number, double significance) {
        return Math.ceil(number / significance) * significance;
    }

    public long COMBIN(int count1, int count2) {
        if (count2 > count1) {
            throw new IllegalArgumentException("Second argument should be smaller the the first argument");
        }
        return MathUtils.factorial(count1) / (MathUtils.factorial(count2) * MathUtils.factorial(count1 - count2));
    }

    public double COS(double number) {
        return Math.cos(number);
    }

    public double COSH(double number) {
        return MathUtils.cosh(number);
    }

    public int COUNTBLANK(Iterator<String> range) {
        int n = 0;
        while (range.hasNext()) {
            String s = range.next();
            if (s == null || s.isEmpty()) {
                n++;
            }
        }
        return n;
    }

    public int COUNTIF(Iterator<String> range, String criteria) {
        int n = 0;
        while (range.hasNext()) {
            String s = range.next();
            if (criteria == null) {
                if (s == null) {
                    n++;
                }
            } else if (criteria.equals(s)) {
                n++;
            }
        }
        return n;
    }

    public double DEGREES(double number) {
        return Math.toDegrees(number);
    }

    private long exactOrNextInteger(double n) {
        double f = Math.floor(n);
        if (n == f) {
            return (long) f;
        }
        return (long) (f + 1);
    }

    /**
     * Rounds the given number up to the nearest even integer.
     * 
     * @param number
     * @return
     */
    public long EVEN(double number) {
        if (number < 0) {
            return -EVEN(-number);
        }
        long n = exactOrNextInteger(number);

        if (n % 2 == 0) {
            return n;
        }
        return n + 1;
    }

    public double EXP(double number) {
        return Math.exp(number);
    }

    public long FACT(int number) {
        return MathUtils.factorial(number);
    }

    public double FACTDOUBLE(int number) {
        return MathUtils.factorialDouble(number);
    }

    public double FLOOR(double number, double significance) {
        return Math.floor(number / significance) * significance;
    }

    /**
     * Returns the greatest common divisor of one or more integers.
     * 
     * @return
     */
    public long GCD(Iterator<Long> values) {
        if (!values.hasNext()) {
            return 1;
        }
        long result = values.next();
        while (values.hasNext()) {
            result = MathUtils.gcd(result, values.next());
        }
        return result;
    }

    public long INT(double number) {
        return Math.round(number);
    }

    public boolean ISEVEN(double value) {
        return ((long) value) % 2 == 0;
    }

    public boolean ISODD(double value) {
        return ((long) value) % 2 == 1;
    }

    /**
     * Returns the least common multiple of one or more integers. Integer_1, integer_2,... integer_30 are integers whose
     * lowest common multiple is to be calculated.
     * 
     * @param values
     * @return
     */
    public long LCM(Iterator<Long> values) {
        if (!values.hasNext()) {
            return 1;
        }
        long result = values.next();
        while (values.hasNext()) {
            result = MathUtils.lcm(result, values.next());
        }
        return result;
    }

    public double LN(double number) {
        return Math.log(number);
    }

    public double LOG(double number, double base) {
        return Math.log(number) / Math.log(base);
    }

    public double LOG10(double number) {
        return Math.log10(number);
    }

    public long MOD(long dividend, long divisor) {
        return dividend % divisor;
    }

    /**
     * The result is the nearest integer multiple of the number.
     * 
     * @param number
     * @param multiple
     * @return
     */
    public double MROUND(double number, double multiple) {
        return Math.round(number / multiple) * multiple;
    }

    /**
     * Returns the factorial of the sum of the arguments divided by the product of the factorials of the arguments.
     * 
     * @param values
     * @return
     */
    public double MULTINOMIAL(Iterator<Integer> values) {
        int sum = 0;
        long product = 1;
        while (values.hasNext()) {
            Integer n = values.next();
            sum += n;
            product *= MathUtils.factorial(n);
        }
        return MathUtils.factorial(sum) / product;
    }

    /**
     * Rounds the given number up to the nearest odd integer.
     * 
     * @param number
     * @return
     */
    public long ODD(double number) {
        if (number < 0) {
            return -ODD(-number);
        }
        long n = exactOrNextInteger(number);
        if (n % 2 == 1) {
            return n;
        }
        return n + 1;
    }

    public double POWER(double base, double power) {
        return Math.pow(base, power);
    }

    public double PRODUCT(Iterator<Double> values) {
        double n = 1;
        while (values.hasNext()) {
            n *= values.next();
        }
        return n;
    }

    public long QUOTIENT(long numerator, long denominator) {
        return numerator / denominator;
    }

    public double RADIANS(double number) {
        return Math.toRadians(number);
    }

    @Function(cacheable = false)
    public double RAND() {
        return Math.random();
    }

    @Function(cacheable = false)
    public double RANDBETWEEN(double bottom, double top) {
        return bottom + (top - bottom) * Math.random();
    }

    /**
     * Rounds the given number to a certain number of decimal places according to valid mathematical criteria. Count
     * (optional) is the number of the places to which the value is to be rounded. If the count parameter is negative,
     * only the whole number portion is rounded. It is rounded to the place indicated by the count.
     * 
     * @param number
     * @return
     */
    public double ROUND(double number, int count) {
        return MathUtils.round(number, count, BigDecimal.ROUND_FLOOR);
    }

    public double ROUNDDOWN(double number, int count) {
        return MathUtils.round(number, count, BigDecimal.ROUND_DOWN);
    }

    public double ROUNDUP(double number, int count) {
        return MathUtils.round(number, count, BigDecimal.ROUND_UP);
    }

    /**
     * Returns a sum of powers of the number x in accordance with the following formula: SERIESSUM(x,n,m,coefficients) =
     * coefficient_1*x^n + coefficient_2*x^(n+m) + coefficient_3*x^(n+2m) +...+ coefficient_i*x^(n+(i-1)m). x is the
     * number as an independent variable. n is the starting power. m is the increment. Coefficients is a series of
     * coefficients. For each coefficient the series sum is extended by one section.
     * 
     * @return
     */
    public double SERIESSUM(double x, double n, double m, Iterator<Double> coefficients) {
        double result = 0;
        double pow = n;
        while (coefficients.hasNext()) {
            result += coefficients.next() * Math.pow(x, pow);
            pow += m;
        }
        return result;
    }

    public double SIGN(double number) {
        return Math.signum(number);
    }

    public double SIN(double number) {
        return Math.sin(number);
    }

    public double SINH(double number) {
        return Math.sinh(number);
    }

    public double SQRT(double number) {
        return Math.sqrt(number);
    }

    /**
     * Returns the square root of the product of the given number and PI.
     * 
     * @param number
     * @return
     */
    public double SQRTPI(double number) {
        return Math.sqrt(number * Math.PI);
    }

    public double TAN(double number) {
        return Math.tan(number);
    }

    public double TANH(double number) {
        return Math.tanh(number);
    }

    public double TRUNC(double number, int count) {
        return MathUtils.round(number, count, BigDecimal.ROUND_DOWN);
    }

    public double SUM(Iterator<Double> values) {
        double sum = 0;
        while (values.hasNext()) {
            sum += values.next();
        }
        return sum;
    }

    /**
     * Adds the cells specified by a given criteria. Range is the range to which the criteria are to be applied.
     * Criteria is the cell in which the search criterion is shown, or the search criterion itself. Sum_range is the
     * range from which values are summed, if it has not been indicated, the values found in the Range are summed.
     * public double SUMIF(range, criteria, sum_range){
     * 
     * }
     */

    public double SUMSQ(Iterator<Double> values) {
        double sum = 0;
        while (values.hasNext()) {
            double x = values.next();
            sum += x * x;
        }
        return sum;
    }

    public double PI() {
        return Math.PI;
    }

    public static void main(String[] args) {
        System.out.println(new MathFunctions().ODD(5.5));
        System.out.println(new MathFunctions().EVEN(12));
    }

}