org.jenetics.internal.math.base Maven / Gradle / Ivy
Show all versions of org.jenetics Show documentation
/*
* Java Genetic Algorithm Library (jenetics-3.1.0).
* Copyright (c) 2007-2015 Franz Wilhelmstötter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author:
* Franz Wilhelmstötter ([email protected])
*/
package org.jenetics.internal.math;
import static java.lang.Double.doubleToLongBits;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import java.util.Random;
import org.jenetics.internal.util.require;
import org.jenetics.util.RandomRegistry;
/**
* This object contains mathematical helper functions.
*
* @author Franz Wilhelmstötter
* @since 1.0
* @version 3.0
*/
public final class base {
private base() {require.noInstance();}
/**
* Clamping a value between a pair of boundary values.
* Note: using clamp with floating point numbers may give unexpected
* results if one of the values is {@code NaN}.
*
* @param v the value to clamp
* @param lo the lower bound.
* @param hi the upper bound.
* @return The clamped value:
*
* - {@code lo if v < lo}
* - {@code hi if hi < v}
* - {@code otherwise, v}
*
*/
public static double clamp(final double v, final double lo, final double hi) {
return v < lo ? lo : (v > hi ? hi : v);
}
/**
* Return the ULP
* distance of the given two double values.
*
* @param a first double.
* @param b second double.
* @return the ULP distance.
* @throws ArithmeticException if the distance doesn't fit in a long value.
*/
public static long ulpDistance(final double a, final double b) {
return Math.subtractExact(ulpPosition(a), ulpPosition(b));
}
/**
* Calculating the ULP
* position of a double number.
*
* {@code
* double a = 0.0;
* for (int i = 0; i < 10; ++i) {
* a = Math.nextAfter(a, Double.POSITIVE_INFINITY);
* }
*
* for (int i = 0; i < 19; ++i) {
* a = Math.nextAfter(a, Double.NEGATIVE_INFINITY);
* System.out.println(
* a + "\t" + ulpPosition(a) + "\t" + ulpDistance(0.0, a)
* );
* }
* }
*
* The code fragment above will create the following output:
*
* 4.4E-323 9 9
* 4.0E-323 8 8
* 3.5E-323 7 7
* 3.0E-323 6 6
* 2.5E-323 5 5
* 2.0E-323 4 4
* 1.5E-323 3 3
* 1.0E-323 2 2
* 4.9E-324 1 1
* 0.0 0 0
* -4.9E-324 -1 1
* -1.0E-323 -2 2
* -1.5E-323 -3 3
* -2.0E-323 -4 4
* -2.5E-323 -5 5
* -3.0E-323 -6 6
* -3.5E-323 -7 7
* -4.0E-323 -8 8
* -4.4E-323 -9 9
*
*
* @param a the double number.
* @return the ULP position.
*/
public static long ulpPosition(final double a) {
long t = doubleToLongBits(a);
if (t < 0) {
t = Long.MIN_VALUE - t;
}
return t;
}
/**
* Selects a random subset of size {@code k} from a set of size {@code n}.
*
* @see #subset(int, int[])
*
* @param n the size of the set.
* @param k the size of the subset.
* @throws IllegalArgumentException if {@code n < k}, {@code k == 0} or if
* {@code n*k} will cause an integer overflow.
* @return the subset array.
*/
public static int[] subset(final int n, final int k) {
return subset(n, k, RandomRegistry.getRandom());
}
/**
* Selects a random subset of size {@code k} from a set of size {@code n}.
*
* @see #subset(int, int[], Random)
*
* @param n the size of the set.
* @param k the size of the subset.
* @param random the random number generator used.
* @throws NullPointerException if {@code random} is {@code null}.
* @throws IllegalArgumentException if {@code n < k}, {@code k == 0} or if
* {@code n*k} will cause an integer overflow.
* @return the subset array.
*/
public static int[] subset(final int n, final int k, final Random random) {
requireNonNull(random, "Random");
if (k <= 0) {
throw new IllegalArgumentException(format(
"Subset size smaller or equal zero: %s", k
));
}
if (n < k) {
throw new IllegalArgumentException(format(
"n smaller than k: %s < %s.", n, k
));
}
final int[] sub = new int[k];
subset(n, sub,random);
return sub;
}
/**
*
* Selects a random subset of size {@code sub.length} from a set of size
* {@code n}.
*
*
*
* Authors:
* FORTRAN77 original version by Albert Nijenhuis, Herbert Wilf. This
* version based on the C++ version by John Burkardt.
*
*
*
* Reference:
* Albert Nijenhuis, Herbert Wilf,
* Combinatorial Algorithms for Computers and Calculators,
* Second Edition,
* Academic Press, 1978,
* ISBN: 0-12-519260-6,
* LC: QA164.N54.
*
*
* @param n the size of the set.
* @param sub the sub set array.
* @throws NullPointerException if {@code sub} is {@code null}.
* @throws IllegalArgumentException if {@code n < sub.length},
* {@code sub.length == 0} or {@code n*sub.length} will cause an
* integer overflow.
*/
public static void subset(final int n, final int sub[]) {
subset(n, sub, RandomRegistry.getRandom());
}
/**
*
* Selects a random subset of size {@code sub.length} from a set of size
* {@code n}.
*
*
*
* Authors:
* FORTRAN77 original version by Albert Nijenhuis, Herbert Wilf. This
* version based on the C++ version by John Burkardt.
*
*
*
* Reference:
* Albert Nijenhuis, Herbert Wilf,
* Combinatorial Algorithms for Computers and Calculators,
* Second Edition,
* Academic Press, 1978,
* ISBN: 0-12-519260-6,
* LC: QA164.N54.
*
*
* @param n the size of the set.
* @param sub the sub set array.
* @param random the random number generator used.
* @return the sub-set array for the given parameter
* @throws NullPointerException if {@code sub} or {@code random} is
* {@code null}.
* @throws IllegalArgumentException if {@code n < sub.length},
* {@code sub.length == 0} or {@code n*sub.length} will cause an
* integer overflow.
*/
public static int[] subset(final int n, final int sub[], final Random random) {
requireNonNull(random, "Random");
requireNonNull(sub, "Sub set array");
final int k = sub.length;
if (k <= 0) {
throw new IllegalArgumentException(format(
"Subset size smaller or equal zero: %s", k
));
}
if (n < k) {
throw new IllegalArgumentException(format(
"n smaller than k: %s < %s.", n, k
));
}
if (!arithmetic.isMultiplicationSave(n, k)) {
throw new IllegalArgumentException(format(
"n*sub.length > Integer.MAX_VALUE (%s*%s = %s > %s)",
n, sub.length, (long)n*(long)k, Integer.MAX_VALUE
));
}
if (sub.length == n) {
for (int i = 0; i < sub.length; ++i) {
sub[i] = i;
}
return sub;
}
for (int i = 0; i < k; ++i) {
sub[i] = (i*n)/k;
}
int l = 0;
int ix = 0;
for (int i = 0; i < k; ++i) {
do {
ix = nextInt(random, 1, n);
l = (ix*k - 1)/n;
} while (sub[l] >= ix);
sub[l] = sub[l] + 1;
}
int m = 0;
int ip = 0;
int is = k;
for (int i = 0; i < k; ++i) {
m = sub[i];
sub[i] = 0;
if (m != (i*n)/k) {
ip = ip + 1;
sub[ip - 1] = m;
}
}
int ihi = ip;
int ids = 0;
for (int i = 1; i <= ihi; ++i) {
ip = ihi + 1 - i;
l = 1 + (sub[ip - 1]*k - 1)/n;
ids = sub[ip - 1] - ((l - 1)*n)/k;
sub[ip - 1] = 0;
sub[is - 1] = l;
is = is - ids;
}
int ir = 0;
int m0 = 0;
for (int ll = 1; ll <= k; ++ll) {
l = k + 1 - ll;
if (sub[l - 1] != 0) {
ir = l;
m0 = 1 + ((sub[l - 1] - 1)*n)/k;
m = (sub[l-1]*n)/k - m0 + 1;
}
ix = nextInt(random, m0, m0 + m - 1);
int i = l + 1;
while (i <= ir && ix >= sub[i - 1]) {
ix = ix + 1;
sub[ i- 2] = sub[i - 1];
i = i + 1;
}
sub[i - 2] = ix;
--m;
}
return sub;
}
private static int nextInt(final Random random, final int a, final int b) {
return a == b ? a - 1 : random.nextInt(b - a) + a;
}
}