net.time4j.base.MathUtils Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2015 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (MathUtils.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see .
* -----------------------------------------------------------------------
*/
package net.time4j.base;
/**
* Defines some mathematical routines which are needed in calendrical
* calculations.
*
* @author Meno Hochschild
*/
/*[deutsch]
* Definiert diverse mathematische Routinen, die in kalendarischen
* Berechnungen gebraucht werden.
*
* @author Meno Hochschild
*/
public final class MathUtils {
//~ Konstruktoren -----------------------------------------------------
private MathUtils() {
// keine Instanzierung
}
//~ Methoden ----------------------------------------------------------
/**
* Performs a safe type-cast to an int-primitive.
*
* @param num long-primitive
* @return int as type-cast
* @throws ArithmeticException if int-range overflows
*/
/*[deutsch]
* Macht einen sicheren TypeCast auf ein int-Primitive.
*
* @param num long-primitive
* @return int as type-cast
* @throws ArithmeticException if int-range overflows
*/
public static int safeCast(long num) {
if (num < Integer.MIN_VALUE || num > Integer.MAX_VALUE) {
throw new ArithmeticException("Out of range: " + num);
} else {
return (int) num;
}
}
/**
* Sums up the numbers with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return sum
* @throws ArithmeticException if int-range overflows
*/
/*[deutsch]
* Addiert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return sum
* @throws ArithmeticException if int-range overflows
*/
public static int safeAdd(
int op1,
int op2
) {
if (op2 == 0) {
return op1;
}
long result = ((long) op1) + ((long) op2);
if ((result < Integer.MIN_VALUE) || (result > Integer.MAX_VALUE)) {
StringBuilder sb = new StringBuilder(32);
sb.append("Integer overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
} else {
return (int) result;
}
}
/**
* Sums up the numbers with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return sum
* @throws ArithmeticException if long-range overflows
*/
/*[deutsch]
* Addiert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return sum
* @throws ArithmeticException if long-range overflows
*/
public static long safeAdd(
long op1,
long op2
) {
if (op2 == 0L) {
return op1;
}
if (
(op2 > 0)
? (op1 > Long.MAX_VALUE - op2)
: (op1 < Long.MIN_VALUE - op2)
) {
StringBuilder sb = new StringBuilder(32);
sb.append("Long overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
}
return op1 + op2;
}
/**
* Subtracts the numbers from each other with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return difference
* @throws ArithmeticException if int-range overflows
*/
/*[deutsch]
* Subtrahiert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return difference
* @throws ArithmeticException if int-range overflows
*/
public static int safeSubtract(
int op1,
int op2
) {
if (op2 == 0) {
return op1;
}
long result = ((long) op1) - ((long) op2);
if ((result < Integer.MIN_VALUE) || (result > Integer.MAX_VALUE)) {
StringBuilder sb = new StringBuilder(32);
sb.append("Integer overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
} else {
return (int) result;
}
}
/**
* Subtracts the numbers from each other with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return difference
* @throws ArithmeticException if long-range overflows
*/
/*[deutsch]
* Subtrahiert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return difference
* @throws ArithmeticException if long-range overflows
*/
public static long safeSubtract(
long op1,
long op2
) {
if (op2 == 0L) {
return op1;
}
if (
(op2 > 0)
? (op1 < Long.MIN_VALUE + op2)
: (op1 > Long.MAX_VALUE + op2)
) {
StringBuilder sb = new StringBuilder(32);
sb.append("Long overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
}
return op1 - op2;
}
/**
* Multiplies the numbers with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return product
* @throws ArithmeticException if int-range overflows
*/
/*[deutsch]
* Multipliziert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return product
* @throws ArithmeticException if int-range overflows
*/
public static int safeMultiply(
int op1,
int op2
) {
if (op2 == 1) {
return op1;
}
long result = ((long) op1) * ((long) op2);
if ((result < Integer.MIN_VALUE) || (result > Integer.MAX_VALUE)) {
StringBuilder sb = new StringBuilder(32);
sb.append("Integer overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
} else {
return (int) result;
}
}
/**
* Multiplies the numbers with range check.
*
* @param op1 first operand
* @param op2 second operand
* @return product
* @throws ArithmeticException if long-range overflows
*/
/*[deutsch]
* Multipliziert die Zahlen mit Überlaufkontrolle.
*
* @param op1 first operand
* @param op2 second operand
* @return product
* @throws ArithmeticException if long-range overflows
*/
public static long safeMultiply(
long op1,
long op2
) {
if (op2 == 1L) {
return op1;
}
if (
(op2 > 0)
? (op1 > Long.MAX_VALUE / op2) || (op1 < Long.MIN_VALUE / op2)
: ((op2 < -1)
? (op1 > Long.MIN_VALUE / op2) || (op1 < Long.MAX_VALUE / op2)
: (op2 == -1) && (op1 == Long.MIN_VALUE))
) {
StringBuilder sb = new StringBuilder(32);
sb.append("Long overflow: (");
sb.append(op1);
sb.append(',');
sb.append(op2);
sb.append(')');
throw new ArithmeticException(sb.toString());
}
return op1 * op2;
}
/**
* Inverts the number with range check.
*
* @param value value to be negated
* @return the expression {@code -value}
* @throws ArithmeticException if int-range overflows
*/
/*[deutsch]
* Prüft auch Extremfälle beim Negieren.
*
* @param value value to be negated
* @return the expression {@code -value}
* @throws ArithmeticException if int-range overflows
*/
public static int safeNegate(int value) {
if (value == Integer.MIN_VALUE) {
throw new ArithmeticException("Not negatable: " + value);
} else {
return -value;
}
}
/**
* Inverts the number with range check.
*
* @param value value to be negated
* @return the expression {@code -value}
* @throws ArithmeticException if long-range overflows
*/
/*[deutsch]
* Prüft auch Extremfälle beim Negieren.
*
* @param value value to be negated
* @return the expression {@code -value}
* @throws ArithmeticException if long-range overflows
*/
public static long safeNegate(long value) {
if (value == Long.MIN_VALUE) {
throw new ArithmeticException("Not negatable: " + value);
} else {
return -value;
}
}
/**
* Returns the largest lower limit of quotient.
*
* Examples:
*
*
* - {@code floorDivide(2, 2) == 1}
* - {@code floorDivide(1, 2) == 0}
* - {@code floorDivide(0, 2) == 0}
* - {@code floorDivide(-1, 2) == -1}
* - {@code floorDivide(-2, 2) == -1}
* - {@code floorDivide(-3, 2) == -2}
*
*
* @param value numerator
* @param divisor divisor
* @return quotient as result of division
*/
/*[deutsch]
* Liefert die größte untere Schranke des Quotienten.
*
* Beispiele:
*
*
* - {@code floorDivide(2, 2) == 1}
* - {@code floorDivide(1, 2) == 0}
* - {@code floorDivide(0, 2) == 0}
* - {@code floorDivide(-1, 2) == -1}
* - {@code floorDivide(-2, 2) == -1}
* - {@code floorDivide(-3, 2) == -2}
*
*
* @param value numerator
* @param divisor divisor
* @return quotient as result of division
*/
public static int floorDivide(
int value,
int divisor
) {
if (value >= 0) {
return (value / divisor);
} else {
return ((value + 1) / divisor) - 1;
}
}
/**
* See {@link #floorDivide(int, int)}.
*
* @param value numerator
* @param divisor divisor
* @return quotient as result of division
*/
/*[deutsch]
* Siehe {@link #floorDivide(int, int)}.
*
* @param value numerator
* @param divisor divisor
* @return quotient as result of division
*/
public static long floorDivide(
long value,
int divisor
) {
if (value >= 0) {
return (value / divisor);
} else {
return ((value + 1) / divisor) - 1;
}
}
/**
* Calculates the remainder based on {@link #floorDivide(int, int)}.
*
* Examples:
*
*
* - {@code floorModulo(2, 2) == 0}
* - {@code floorModulo(1, 2) == 1}
* - {@code floorModulo(0, 2) == 0}
* - {@code floorModulo(-1, 2) == 1}
* - {@code floorModulo(-2, 2) == 0}
* - {@code floorModulo(-3, 2) == 1}
*
*
* @param value numerator
* @param divisor divisor
* @return remainder of division (never negative if divisor is positive)
*/
/*[deutsch]
* Modulo-Operator, der den Divisionsrest auf Basis von
* {@link #floorDivide(int, int)} berechnet.
*
* Beispiele:
*
*
* - {@code floorModulo(2, 2) == 0}
* - {@code floorModulo(1, 2) == 1}
* - {@code floorModulo(0, 2) == 0}
* - {@code floorModulo(-1, 2) == 1}
* - {@code floorModulo(-2, 2) == 0}
* - {@code floorModulo(-3, 2) == 1}
*
*
* @param value numerator
* @param divisor divisor
* @return remainder of division (never negative if divisor is positive)
*/
public static int floorModulo(
int value,
int divisor
) {
return (value - divisor * (floorDivide(value, divisor)));
}
/**
* See {@link #floorModulo(int, int)}.
*
* @param value numerator
* @param divisor divisor
* @return remainder of division (never negative if divisor is positive)
*/
/*[deutsch]
* Siehe {@link #floorModulo(int, int)}.
*
* @param value numerator
* @param divisor divisor
* @return remainder of division (never negative if divisor is positive)
*/
public static int floorModulo(
long value,
int divisor
) {
long ret = (value - divisor * (floorDivide(value, divisor)));
return (int) ret; // Type-Cast hier wegen modulo-Semantik sicher
}
}