org.renjin.primitives.MathExt.java Source code

Java tutorial

Introduction

Here is the source code for org.renjin.primitives.MathExt.java

Source

/*
 * R : A Computer Language for Statistical Data Analysis
 * Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
 * Copyright (C) 1997--2008  The R Development Core Team
 * Copyright (C) 2003, 2004  The R Foundation
 * Copyright (C) 2010 bedatadriven
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.renjin.primitives;

import org.apache.commons.math.complex.Complex;
import org.apache.commons.math.special.Beta;
import org.apache.commons.math.special.Gamma;
import org.apache.commons.math.util.MathUtils;
import org.renjin.invoke.annotations.*;
import org.renjin.sexp.DoubleVector;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

/**
 * Math functions not found in java.Math or apache commons math
 */
public class MathExt {

    private static final int DBL_MAX_10_EXP = 308;

    private static final int MAX_DIGITS = DBL_MAX_10_EXP;

    private MathExt() {
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double gamma(double x) {
        return Math.exp(Gamma.logGamma(x));
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double lgamma(double x) {
        return Gamma.logGamma(x);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double sign(double x) {
        return Math.signum(x);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double log(double x, double base) {

        //Method cannot be called directly as R and Apache Commons Math argument order
        // are reversed
        return MathUtils.log(base, x);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double log(double d) {
        return Math.log(d);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double log2(double d) {
        return MathUtils.log(2, d);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double abs(double x) {
        return Math.abs(x);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double asinh(double val) {
        return (Math.log(val + Math.sqrt(val * val + 1)));
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double acosh(double val) {
        return (Math.log(val + Math.sqrt(val + 1) * Math.sqrt(val - 1)));
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double atanh(double val) {
        return (0.5 * Math.log((1 + val) / (1 - val)));
    }

    @Deferrable
    @Internal
    @DataParallel
    public static double atan2(double y, double x) {
        return (Math.atan2(y, x));
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double signif(double x, int digits) {
        return new BigDecimal(x).round(new MathContext(digits, RoundingMode.HALF_UP)).doubleValue();
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double expm1(double x) {
        return Math.expm1(x);
    }

    @Deferrable
    @Builtin
    @DataParallel
    public static double log1p(double x) {
        return Math.log1p(x);
    }

    @Internal
    @Deferrable
    @DataParallel
    public static double beta(double a, double b) {
        return (Math.exp(Beta.logBeta(a, b)));
    }

    @Internal
    @Deferrable
    @DataParallel
    public static double lbeta(double a, double b) {
        return (Beta.logBeta(a, b));
    }

    @Internal
    @DataParallel
    public static double choose(double n, int k) {
        /*
         * Because gamma(a+1) = factorial(a)
         * we use gamma(n+1) /(gamma(n-k+1) * gamma(k+1)) instead of
         * Binomial(n,k) = n! / ((n-k)! * k!) for non-integer n values.
         * 
         */
        if (k < 0) {
            return (0);
        } else if (k == 0) {
            return (1);
        } else if ((int) n == n) {
            return (MathUtils.binomialCoefficientDouble((int) n, k));
        } else {
            return (MathExt.gamma(n + 1) / (MathExt.gamma(n - k + 1) * MathExt.gamma(k + 1)));
        }
    }

    @Internal
    @DataParallel
    public static double lchoose(double n, int k) {
        return (Math.log(choose(n, k)));
    }

    // our wrapper generator gets confused by the two double & float overloads
    // of Math.round
    @Builtin
    @Deferrable
    @DataParallel
    public static double round(double x) {
        return Math.rint(x);
    }

    @Builtin
    @Deferrable
    @DataParallel
    public static double round(double x, int digits) {
        // adapted from the nmath library, fround.c

        double sign;
        int dig;

        if (Double.isNaN(x) || Double.isNaN(digits)) {
            return x + digits;
        }
        if (!DoubleVector.isFinite(x)) {
            return x;
        }

        if (digits == Double.POSITIVE_INFINITY) {
            return x;
        } else if (digits == Double.NEGATIVE_INFINITY) {
            return 0.0;
        }

        if (digits > MAX_DIGITS) {
            digits = MAX_DIGITS;
        }
        dig = (int) Math.floor(digits + 0.5);

        if (x < 0.) {
            sign = -1.;
            x = -x;
        } else {
            sign = 1.;
        }
        if (dig == 0) {
            return sign * Math.rint(x);
        } else if (dig > 0) {
            // round to a specific number of decimal places
            return sign * new BigDecimal(x).setScale(digits, RoundingMode.HALF_EVEN).doubleValue();
        } else {
            // round to the nearest power of 10
            double pow10 = Math.pow(10., -dig);
            return sign * Math.rint(x / pow10) * pow10;
        }
    }

    @Builtin
    @Deferrable
    @DataParallel
    public static Complex round(Complex x, int digits) {
        return new Complex(round(x.getReal(), digits), round(x.getImaginary(), digits));
    }

    @Generic
    @Deferrable
    @Builtin("trunc")
    @DataParallel
    public static double truncate(double x) {
        return Math.floor(x);
    }
}