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

org.neo4j.values.utils.ValueMath 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.values.utils;

import static org.neo4j.values.storable.Values.doubleValue;
import static org.neo4j.values.storable.Values.longValue;

import org.neo4j.values.storable.DoubleValue;
import org.neo4j.values.storable.IntegralValue;
import org.neo4j.values.storable.LongValue;
import org.neo4j.values.storable.NumberValue;
import org.neo4j.values.storable.Values;

/**
 * Helper methods for doing math on Values
 */
public final class ValueMath {
    public static final int HASH_CONSTANT = 31;

    private ValueMath() {
        throw new UnsupportedOperationException("Do not instantiate");
    }

    /**
     * Overflow safe addition of two longs
     *
     * @param a left-hand operand
     * @param b right-hand operand
     * @return a + b
     */
    public static LongValue add(long a, long b) {
        return longValue(Math.addExact(a, b));
    }

    /**
     * Overflow safe addition of two number values.
     *
     * Will not overflow but instead widen the type as necessary.
     * @param a left-hand operand
     * @param b right-hand operand
     * @return a + b
     */
    public static NumberValue overflowSafeAdd(NumberValue a, NumberValue b) {
        if (a instanceof IntegralValue && b instanceof IntegralValue) {
            return overflowSafeAdd(a.longValue(), b.longValue());
        } else {
            return a.plus(b);
        }
    }

    /**
     * Overflow safe addition of two longs
     * 

* If the result doesn't fit in a long we widen type to use double instead. * * @param a left-hand operand * @param b right-hand operand * @return a + b */ public static NumberValue overflowSafeAdd(long a, long b) { long r = a + b; // Check if result overflows if (((a ^ r) & (b ^ r)) < 0) { return Values.doubleValue((double) a + (double) b); } return longValue(r); } /** * Addition of two doubles * * @param a left-hand operand * @param b right-hand operand * @return a + b */ public static DoubleValue add(double a, double b) { return Values.doubleValue(a + b); } /** * Overflow safe subtraction of two longs * * @param a left-hand operand * @param b right-hand operand * @return a - b */ public static LongValue subtract(long a, long b) { return longValue(Math.subtractExact(a, b)); } /** * Overflow safe subtraction of two longs *

* If the result doesn't fit in a long we widen type to use double instead. * * @param a left-hand operand * @param b right-hand operand * @return a - b */ public static NumberValue overflowSafeSubtract(long a, long b) { long r = a - b; // Check if result overflows if (((a ^ b) & (a ^ r)) < 0) { return Values.doubleValue((double) a - (double) b); } return longValue(r); } /** * Subtraction of two doubles * * @param a left-hand operand * @param b right-hand operand * @return a - b */ public static DoubleValue subtract(double a, double b) { return Values.doubleValue(a - b); } /** * Overflow safe multiplication of two longs * * @param a left-hand operand * @param b right-hand operand * @return a * b */ public static LongValue multiply(long a, long b) { return longValue(Math.multiplyExact(a, b)); } /** * Overflow safe multiplication of two longs *

* If the result doesn't fit in a long we widen type to use double instead. * * @param a left-hand operand * @param b right-hand operand * @return a * b */ public static NumberValue overflowSafeMultiply(long a, long b) { long r = a * b; // Check if result overflows long aa = Math.abs(a); long ab = Math.abs(b); if ((aa | ab) >>> 31 != 0) { if (((b != 0) && (r / b != a)) || (a == Long.MIN_VALUE && b == -1)) { return doubleValue((double) a * (double) b); } } return longValue(r); } /** * Multiplication of two doubles * * @param a left-hand operand * @param b right-hand operand * @return a * b */ public static DoubleValue multiply(double a, double b) { return Values.doubleValue(a * b); } private static boolean oppositeInfinites(double a, double b) { return a == Double.POSITIVE_INFINITY && b == Double.NEGATIVE_INFINITY || a == Double.NEGATIVE_INFINITY && b == Double.POSITIVE_INFINITY; } /** Calculates an incremental average taking into account NaN and +/-Infinity */ public static double incrementalAverage(double runningDbl, double newDbl, double weight) { double result = runningDbl + (newDbl - runningDbl) / weight; if (Double.isNaN(result) || Double.isInfinite(result)) { // If the result is NaN we need to take some care to figure out if it should // be +-Infinity or NaN. We assume this is rare so we only do the extra checking // in that case return incrementalAverageSlowRoute(runningDbl, newDbl, weight); } else { return result; } } private static double incrementalAverageSlowRoute(double runningDbl, double newDbl, double weight) { if (Double.isNaN(runningDbl) || Double.isNaN(newDbl)) { return Double.NaN; } boolean newInfinite = Double.isInfinite(newDbl); boolean runningInfinite = Double.isInfinite(runningDbl); if (!newInfinite && !runningInfinite) { return runningDbl + (newDbl - runningDbl) / weight; } if (newInfinite && !runningInfinite) { return newDbl; } if (!newInfinite) { return runningDbl; } if (oppositeInfinites(newDbl, runningDbl)) { return Double.NaN; } return runningDbl; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy