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

org.neo4j.internal.helpers.MathUtil Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j 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 .
 */
package org.neo4j.internal.helpers;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Comparator;
import org.neo4j.util.Preconditions;

public final class MathUtil {
    public static final double DEFAULT_EPSILON = 1.0E-8;

    private static final long NON_DOUBLE_LONG = 0xFFE0_0000_0000_0000L; // doubles are exact integers up to 53 bits

    private MathUtil() {
        throw new AssertionError();
    }

    /**
     * Clamp the given value between the two given bounds.
     *
     * @param value  the value to clamp
     * @param lowerBound the lower boundary to clamp {@code value}
     * @param upperBound the upper boundary to clamp {@code value}
     * @return {@code value} if {@code value} is in between the bounds, otherwise the closest bound
     * @throws IllegalArgumentException when {@code lowerBound > upperBound}
     */
    public static int clamp(int value, int lowerBound, int upperBound) {
        Preconditions.checkArgument(
                lowerBound <= upperBound,
                "given lower bound, %d; is greater than given upper bound, %d.",
                lowerBound,
                upperBound);
        return Math.max(lowerBound, Math.min(value, upperBound));
    }

    /**
     * Clamp the given value between the two given bounds.
     *
     * @param value the value to clamp
     * @param lowerBound the lower boundary to clamp {@code value}
     * @param upperBound the upper boundary to clamp {@code value}
     * @return {@code value} if {@code value} is in between the bounds, otherwise the closest bound
     * @throws IllegalArgumentException when {@code lowerBound > upperBound}
     */
    public static long clamp(long value, long lowerBound, long upperBound) {
        Preconditions.checkArgument(
                lowerBound <= upperBound,
                "given lower bound, %d; is greater than given upper bound, %d.",
                lowerBound,
                upperBound);
        return Math.max(lowerBound, Math.min(value, upperBound));
    }

    /**
     * Clamp the given value between the two given bounds.
     *
     * @param value the value to clamp
     * @param lowerBound the lower boundary to clamp {@code value}
     * @param upperBound the upper boundary to clamp {@code value}
     * @return {@code value} if {@code value} is in between the bounds, otherwise the closest bound
     * @throws IllegalArgumentException when {@code lowerBound > upperBound}
     */
    public static float clamp(float value, float lowerBound, float upperBound) {
        Preconditions.checkArgument(
                lowerBound <= upperBound,
                "given lower bound, %g; is greater than given upper bound, %g.",
                lowerBound,
                upperBound);
        return Math.max(lowerBound, Math.min(value, upperBound));
    }

    /**
     * Clamp the given value between the two given bounds.
     *
     * @param value the value to clamp
     * @param lowerBound the lower boundary to clamp {@code value}
     * @param upperBound the upper boundary to clamp {@code value}
     * @return {@code value} if {@code value} is in between the bounds, otherwise the closest bound
     * @throws IllegalArgumentException when {@code lowerBound > upperBound}
     */
    public static double clamp(double value, double lowerBound, double upperBound) {
        Preconditions.checkArgument(
                lowerBound <= upperBound,
                "given lower bound, %g; is greater than given upper bound, %g.",
                lowerBound,
                upperBound);
        return Math.max(lowerBound, Math.min(value, upperBound));
    }

    /**
     * Calculates the portion of the first value to all values passed
     * @param n The values in the set
     * @return the ratio of n[0] to the sum all n, 0 if result is {@link Double#NaN}
     */
    public static double portion(double... n) {
        assert n.length > 0;

        double first = n[0];
        if (Math.abs(first) < DEFAULT_EPSILON) {
            return 0d;
        }
        double total = Arrays.stream(n).sum();
        return first / total;
    }

    // Tested by PropertyValueComparisonTest
    public static int compareDoubleAgainstLong(double lhs, long rhs) {
        if ((NON_DOUBLE_LONG & rhs) != NON_DOUBLE_LONG) {
            if (Double.isNaN(lhs)) {
                return +1;
            }
            if (Double.isInfinite(lhs)) {
                return lhs < 0 ? -1 : +1;
            }
            return BigDecimal.valueOf(lhs).compareTo(BigDecimal.valueOf(rhs));
        }
        return Double.compare(lhs, rhs);
    }

    public static int ceil(int dividend, int divisor) {
        return ((dividend - 1) / divisor) + 1;
    }

    public static long ceil(long dividend, long divisor) {
        return ((dividend - 1) / divisor) + 1;
    }

    /**
     * Compares two numbers given some amount of allowed error.
     */
    public static int compare(double x, double y, double eps) {
        return equals(x, y, eps) ? 0 : x < y ? -1 : 1;
    }

    /**
     * Returns true if both arguments are equal or within the range of allowed error (inclusive)
     */
    public static boolean equals(double x, double y, double eps) {
        return Math.abs(x - y) <= eps;
    }

    public static class CommonToleranceComparator implements Comparator {
        private final double epsilon;

        public CommonToleranceComparator(double epsilon) {
            this.epsilon = epsilon;
        }

        @Override
        public int compare(Double x, Double y) {
            return MathUtil.compare(x, y, epsilon);
        }
    }

    /**
     * Round a non-negative value up to the next multiple of a specified number.
     * @param value to round up.
     * @param multiplier
     * @return rounded up value.
     */
    public static long roundUp(long value, long multiplier) {
        return (value + multiplier - 1) / multiplier * multiplier;
    }

    /**
     * Ported from FdLibm to Java. See {@link StrictMath} for additional details
     * 
     * ====================================================
     * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
     *
     * Developed at SunSoft, a Sun Microsystems, Inc. business.
     * Permission to use, copy, modify, and distribute this
     * software is freely granted, provided that this notice
     * is preserved.
     * ====================================================
     * 
*/ public static final class Erf { // Coefficients for approximation to erf on [0,0.84375] private static final double PP0 = 1.28379167095512558561e-01; // 0x3FC06EBA, 0x8214DB68 private static final double PP1 = -3.25042107247001499370e-01; // 0xBFD4CD7D, 0x691CB913 private static final double PP2 = -2.84817495755985104766e-02; // 0xBF9D2A51, 0xDBD7194F private static final double PP3 = -5.77027029648944159157e-03; // 0xBF77A291, 0x236668E4 private static final double PP4 = -2.37630166566501626084e-05; // 0xBEF8EAD6, 0x120016AC private static final double QQ1 = 3.97917223959155352819e-01; // 0x3FD97779, 0xCDDADC09 private static final double QQ2 = 6.50222499887672944485e-02; // 0x3FB0A54C, 0x5536CEBA private static final double QQ3 = 5.08130628187576562776e-03; // 0x3F74D022, 0xC4D36B0F private static final double QQ4 = 1.32494738004321644526e-04; // 0x3F215DC9, 0x221C1A10 private static final double QQ5 = -3.96022827877536812320e-06; // 0xBED09C43, 0x42A26120 // Coefficients for approximation to erf in [0.84375,1.25] private static final double PA0 = -2.36211856075265944077e-03; // 0xBF6359B8, 0xBEF77538 private static final double PA1 = 4.14856118683748331666e-01; // 0x3FDA8D00, 0xAD92B34D private static final double PA2 = -3.72207876035701323847e-01; // 0xBFD7D240, 0xFBB8C3F1 private static final double PA3 = 3.18346619901161753674e-01; // 0x3FD45FCA, 0x805120E4 private static final double PA4 = -1.10894694282396677476e-01; // 0xBFBC6398, 0x3D3E28EC private static final double PA5 = 3.54783043256182359371e-02; // 0x3FA22A36, 0x599795EB private static final double PA6 = -2.16637559486879084300e-03; // 0xBF61BF38, 0x0A96073F private static final double QA1 = 1.06420880400844228286e-01; // 0x3FBB3E66, 0x18EEE323 private static final double QA2 = 5.40397917702171048937e-01; // 0x3FE14AF0, 0x92EB6F33 private static final double QA3 = 7.18286544141962662868e-02; // 0x3FB2635C, 0xD99FE9A7 private static final double QA4 = 1.26171219808761642112e-01; // 0x3FC02660, 0xE763351F private static final double QA5 = 1.36370839120290507362e-02; // 0x3F8BEDC2, 0x6B51DD1C private static final double QA6 = 1.19844998467991074170e-02; // 0x3F888B54, 0x5735151D // Coefficients for approximation to erfc in [1.25,1/0.35] private static final double RA0 = -9.86494403484714822705e-03; // 0xBF843412, 0x600D6435 private static final double RA1 = -6.93858572707181764372e-01; // 0xBFE63416, 0xE4BA7360 private static final double RA2 = -1.05586262253232909814e+01; // 0xC0251E04, 0x41B0E726 private static final double RA3 = -6.23753324503260060396e+01; // 0xC04F300A, 0xE4CBA38D private static final double RA4 = -1.62396669462573470355e+02; // 0xC0644CB1, 0x84282266 private static final double RA5 = -1.84605092906711035994e+02; // 0xC067135C, 0xEBCCABB2 private static final double RA6 = -8.12874355063065934246e+01; // 0xC0545265, 0x57E4D2F2 private static final double RA7 = -9.81432934416914548592e+00; // 0xC023A0EF, 0xC69AC25C private static final double SA1 = 1.96512716674392571292e+01; // 0x4033A6B9, 0xBD707687 private static final double SA2 = 1.37657754143519042600e+02; // 0x4061350C, 0x526AE721 private static final double SA3 = 4.34565877475229228821e+02; // 0x407B290D, 0xD58A1A71 private static final double SA4 = 6.45387271733267880336e+02; // 0x40842B19, 0x21EC2868 private static final double SA5 = 4.29008140027567833386e+02; // 0x407AD021, 0x57700314 private static final double SA6 = 1.08635005541779435134e+02; // 0x405B28A3, 0xEE48AE2C private static final double SA7 = 6.57024977031928170135e+00; // 0x401A47EF, 0x8E484A93 private static final double SA8 = -6.04244152148580987438e-02; // 0xBFAEEFF2, 0xEE749A62 // Coefficients for approximation to erfc in [1/.35,28] private static final double RB0 = -9.86494292470009928597e-03; // 0xBF843412, 0x39E86F4A private static final double RB1 = -7.99283237680523006574e-01; // 0xBFE993BA, 0x70C285DE private static final double RB2 = -1.77579549177547519889e+01; // 0xC031C209, 0x555F995A private static final double RB3 = -1.60636384855821916062e+02; // 0xC064145D, 0x43C5ED98 private static final double RB4 = -6.37566443368389627722e+02; // 0xC083EC88, 0x1375F228 private static final double RB5 = -1.02509513161107724954e+03; // 0xC0900461, 0x6A2E5992 private static final double RB6 = -4.83519191608651397019e+02; // 0xC07E384E, 0x9BDC383F private static final double SB1 = 3.03380607434824582924e+01; // 0x403E568B, 0x261D5190 private static final double SB2 = 3.25792512996573918826e+02; // 0x40745CAE, 0x221B9F0A private static final double SB3 = 1.53672958608443695994e+03; // 0x409802EB, 0x189D5118 private static final double SB4 = 3.19985821950859553908e+03; // 0x40A8FFB7, 0x688C246A private static final double SB5 = 2.55305040643316442583e+03; // 0x40A3F219, 0xCEDF3BE6 private static final double SB6 = 4.74528541206955367215e+02; // 0x407DA874, 0xE79FE763 private static final double SB7 = -2.24409524465858183362e+01; // 0xC03670E2, 0x42712D62 private static final double TINY = 1e-300; private static final double ONE = 1.00000000000000000000e+00; // 0x3FF00000, 0x00000000 private static final double ERX = 8.45062911510467529297e-01; // 0x3FEB0AC1, 0x60000000 private static final double EFX = 1.28379167095512586316e-01; // 0x3FC06EBA, 0x8214DB69 private static final double EFX8 = 1.02703333676410069053e+00; // 0x3FF06EBA, 0x8214DB69 private Erf() {} public static double erf(double x) { int hx = (int) (Double.doubleToRawLongBits(x) >> 32); // high word of x int ix = hx & 0x7fffffff; // high word of |x| if (ix >= 0x7ff00000) { // erf(nan) = nan int i = (hx >>> 31) << 1; return (double) (1 - i) + ONE / x; // erf(+-inf) = +-1 } if (ix < 0x3feb0000) { // |x| < 0.84375 if (ix < 0x3e300000) { // |x| < 2**-28 if (ix < 0x00800000) { return 0.125 * (8.0 * x + EFX8 * x); // avoid underflow } return x + EFX * x; } double z = x * x; double r = PP0 + z * (PP1 + z * (PP2 + z * (PP3 + z * PP4))); double s = ONE + z * (QQ1 + z * (QQ2 + z * (QQ3 + z * (QQ4 + z * QQ5)))); double y = r / s; return x + x * y; } if (ix < 0x3ff40000) { // 0.84375 <= |x| < 1.25 double s = Math.abs(x) - ONE; double P = PA0 + s * (PA1 + s * (PA2 + s * (PA3 + s * (PA4 + s * (PA5 + s * PA6))))); double Q = ONE + s * (QA1 + s * (QA2 + s * (QA3 + s * (QA4 + s * (QA5 + s * QA6))))); if (hx >= 0) { return ERX + P / Q; } return -ERX - P / Q; } if (ix >= 0x40180000) { // inf > |x| >= 6 if (hx >= 0) { return ONE - TINY; } return TINY - ONE; } x = Math.abs(x); double s = ONE / (x * x); double R; double S; if (ix < 0x4006DB6E) { // |x| < 1/0.35 R = RA0 + s * (RA1 + s * (RA2 + s * (RA3 + s * (RA4 + s * (RA5 + s * (RA6 + s * RA7)))))); S = ONE + s * (SA1 + s * (SA2 + s * (SA3 + s * (SA4 + s * (SA5 + s * (SA6 + s * (SA7 + s * SA8))))))); } else { // |x| >= 1/0.35 R = RB0 + s * (RB1 + s * (RB2 + s * (RB3 + s * (RB4 + s * (RB5 + s * RB6))))); S = ONE + s * (SB1 + s * (SB2 + s * (SB3 + s * (SB4 + s * (SB5 + s * (SB6 + s * SB7)))))); } double z = Double.longBitsToDouble(Double.doubleToRawLongBits(x) & 0x00000000FFFFFFFFL); double r = Math.exp(-z * z - 0.5625) * Math.exp((z - x) * (z + x) + R / S); if (hx >= 0) { return ONE - r / x; } return r / x - ONE; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy