Math2.java
package org.djunits.util;
import java.util.Arrays;
/**
* Math2 contains a few utility methods that are missing in the Math package.
* <p>
* Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
* distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
* @author Alexander Verbraeck
*/
public final class Math2
{
/** */
private Math2()
{
}
/**
* Return the maximum value within an array of values.
* @param dn zero or more values
* @return the maximum value of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double max(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double max = dn[0];
for (double d : dn)
{
max = Math.max(max, d);
}
return max;
}
/**
* Return the minimum value within an array of values.
* @param dn zero or more values
* @return the minimum value of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double min(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double min = dn[0];
for (double d : dn)
{
min = Math.min(min, d);
}
return min;
}
/**
* Return the maximum absolute value within an array of values.
* @param dn zero or more values
* @return the maximum absolute value of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double maxAbs(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double max = Math.abs(dn[0]);
for (double d : dn)
{
max = Math.max(max, Math.abs(d));
}
return max;
}
/**
* Return the mimimum absolute value within an array of values.
* @param dn zero or more values
* @return the minimum absolute value of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double minAbs(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double min = Math.abs(dn[0]);
for (double d : dn)
{
min = Math.min(min, Math.abs(d));
}
return min;
}
/**
* Return the sum of the values of an array of values.
* @param dn zero or more values
* @return the sum of the values of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double sum(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double sum = 0.0;
for (double d : dn)
sum += d;
return sum;
}
/**
* Return the sum of the absolute values of an array of values.
* @param dn zero or more values
* @return the sum of the absolute values of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double sumAbs(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double sum = 0.0;
for (double d : dn)
sum += Math.abs(d);
return sum;
}
/**
* Return the sum of the squares of the values of an array of values.
* @param dn zero or more values
* @return the sum of the squares of the values of the arguments
*/
@SuppressWarnings("checkstyle:needbraces")
public static double sumSqr(final double... dn)
{
if (dn == null || dn.length == 0)
return Double.NaN;
double sqrsum = 0.0;
for (double d : dn)
sqrsum += d * d;
return sqrsum;
}
/**
* Computes the median of the provided values, skipping NaN entries.
* <p>
* Rules:
* <ul>
* <li>NaN values are ignored.</li>
* <li>If there are 0 valid (non-NaN) values, {@code Double.NaN} is returned.</li>
* <li>For an odd count, returns the middle value after sorting.</li>
* <li>For an even count, returns the arithmetic mean of the two middle values.</li>
* </ul>
* @param d values to consider; NaNs are skipped
* @return the median as defined above, or {@code Double.NaN} if no valid values
*/
@SuppressWarnings("checkstyle:needbraces")
public static double median(final double... d)
{
if (d == null || d.length == 0)
return Double.NaN;
// Count non-NaN values
int count = 0;
for (double v : d)
if (!Double.isNaN(v))
count++;
if (count == 0)
return Double.NaN;
// Compact non-NaNs into a new array
final double[] a = new double[count];
int idx = 0;
for (double v : d)
if (!Double.isNaN(v))
a[idx++] = v;
Arrays.sort(a);
if ((count & 1) == 1)
{
double m = a[count >>> 1];
return m;
}
else
{
int hiIndex = count >>> 1;
double lo = a[hiIndex - 1];
double hi = a[hiIndex];
double avg = lo + (hi - lo) * 0.5;
return avg;
}
}
/**
* Computes base^exp for integers.
* @param base the integer base
* @param exp the non-negative exponent
* @return base raised to the power exp
*/
public static int pow(final int base, final int exp)
{
int b = base;
int e = exp;
if (e < 0)
{
throw new IllegalArgumentException("Exponent must be non-negative");
}
int result = 1;
while (e > 0)
{
if ((e & 1) == 1)
{
result *= b;
}
b *= b;
e >>= 1; // divide exponent by 2
}
return result;
}
}