/* * ----------------------------------------------------------------------- * Copyright © 2013-2014 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * 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 <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.base; /** * <p>Defines some mathematical routines which are needed in calendrical * calculations. </p> * * @author Meno Hochschild */ /*[deutsch] * <p>Definiert diverse mathematische Routinen, die in kalendarischen * Berechnungen gebraucht werden. </p> * * @author Meno Hochschild */ public final class MathUtils { //~ Konstruktoren ----------------------------------------------------- private MathUtils() { // keine Instanzierung } //~ Methoden ---------------------------------------------------------- /** * <p>Performs a safe type-cast to an int-primitive. </p> * * @param num long-primitive * @return int as type-cast * @throws ArithmeticException if int-range overflows */ /*[deutsch] * <p>Macht einen sicheren TypeCast auf ein int-Primitive. </p> * * @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; } } /** * <p>Sums up the numbers with range check. </p> * * @param op1 first operand * @param op2 second operand * @return sum * @throws ArithmeticException if int-range overflows */ /*[deutsch] * <p>Addiert die Zahlen mit Überlaufkontrolle. </p> * * @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; } } /** * <p>Sums up the numbers with range check. </p> * * @param op1 first operand * @param op2 second operand * @return sum * @throws ArithmeticException if long-range overflows */ /*[deutsch] * <p>Addiert die Zahlen mit Überlaufkontrolle. </p> * * @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; } /** * <p>Subtracts the numbers from each other with range check. </p> * * @param op1 first operand * @param op2 second operand * @return difference * @throws ArithmeticException if int-range overflows */ /*[deutsch] * <p>Subtrahiert die Zahlen mit Überlaufkontrolle. </p> * * @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; } } /** * <p>Subtracts the numbers from each other with range check. </p> * * @param op1 first operand * @param op2 second operand * @return difference * @throws ArithmeticException if long-range overflows */ /*[deutsch] * <p>Subtrahiert die Zahlen mit Überlaufkontrolle. </p> * * @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; } /** * <p>Multiplies the numbers with range check. </p> * * @param op1 first operand * @param op2 second operand * @return product * @throws ArithmeticException if int-range overflows */ /*[deutsch] * <p>Multipliziert die Zahlen mit Überlaufkontrolle. </p> * * @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; } } /** * <p>Multiplies the numbers with range check. </p> * * @param op1 first operand * @param op2 second operand * @return product * @throws ArithmeticException if long-range overflows */ /*[deutsch] * <p>Multipliziert die Zahlen mit Überlaufkontrolle. </p> * * @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; } /** * <p>Inverts the number with range check. </p> * * @param value value to be negated * @return the expression {@code -value} * @throws ArithmeticException if int-range overflows */ /*[deutsch] * <p>Prüft auch Extremfälle beim Negieren. </p> * * @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; } } /** * <p>Inverts the number with range check. </p> * * @param value value to be negated * @return the expression {@code -value} * @throws ArithmeticException if long-range overflows */ /*[deutsch] * <p>Prüft auch Extremfälle beim Negieren. </p> * * @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; } } /** * <p>Returns the largest lower limit of quotient. </p> * * <p>Examples: </p> * * <ul> * <li>{@code floorDivide(2, 2) == 1}</li> * <li>{@code floorDivide(1, 2) == 0}</li> * <li>{@code floorDivide(0, 2) == 0}</li> * <li>{@code floorDivide(-1, 2) == -1}</li> * <li>{@code floorDivide(-2, 2) == -1}</li> * <li>{@code floorDivide(-3, 2) == -2}</li> * </ul> * * @param value numerator * @param divisor divisor * @return quotient as result of division */ /*[deutsch] * <p>Liefert die größte untere Schranke des Quotienten. </p> * * <p>Beispiele: </p> * * <ul> * <li>{@code floorDivide(2, 2) == 1}</li> * <li>{@code floorDivide(1, 2) == 0}</li> * <li>{@code floorDivide(0, 2) == 0}</li> * <li>{@code floorDivide(-1, 2) == -1}</li> * <li>{@code floorDivide(-2, 2) == -1}</li> * <li>{@code floorDivide(-3, 2) == -2}</li> * </ul> * * @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; } } /** * <p>See {@link #floorDivide(int, int)}. </p> * * @param value numerator * @param divisor divisor * @return quotient as result of division */ /*[deutsch] * <p>Siehe {@link #floorDivide(int, int)}. </p> * * @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; } } /** * <p>Calculates the remainder based on {@link #floorDivide(int, int)}. </p> * * <p>Examples: </p> * * <ul> * <li>{@code floorModulo(2, 2) == 0}</li> * <li>{@code floorModulo(1, 2) == 1}</li> * <li>{@code floorModulo(0, 2) == 0}</li> * <li>{@code floorModulo(-1, 2) == 1}</li> * <li>{@code floorModulo(-2, 2) == 0}</li> * <li>{@code floorModulo(-3, 2) == 1}</li> * </ul> * * @param value numerator * @param divisor divisor * @return remainder of division (never negative if divisor is positive) */ /*[deutsch] * <p>Modulo-Operator, der den Divisionsrest auf Basis von * {@link #floorDivide(int, int)} berechnet. </p> * * <p>Beispiele: </p> * * <ul> * <li>{@code floorModulo(2, 2) == 0}</li> * <li>{@code floorModulo(1, 2) == 1}</li> * <li>{@code floorModulo(0, 2) == 0}</li> * <li>{@code floorModulo(-1, 2) == 1}</li> * <li>{@code floorModulo(-2, 2) == 0}</li> * <li>{@code floorModulo(-3, 2) == 1}</li> * </ul> * * @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))); } /** * <p>See {@link #floorModulo(int, int)}. </p> * * @param value numerator * @param divisor divisor * @return remainder of division (never negative if divisor is positive) */ /*[deutsch] * <p>Siehe {@link #floorModulo(int, int)}. </p> * * @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 } }