org.evosuite.instrumentation.error.ErrorConditionChecker Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite 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 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite 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 Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see .
*/
/**
*
*/
package org.evosuite.instrumentation.error;
import java.math.BigDecimal;
import org.objectweb.asm.Opcodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* ErrorConditionChecker class.
*
*
* @author fraser
*/
public class ErrorConditionChecker {
private static final Logger logger = LoggerFactory.getLogger(ErrorConditionChecker.class);
/**
*
* scale
*
*
* @param value
* a float.
* @return a int.
*/
public static int scale(float value) {
return (Integer.MAX_VALUE - 2) * (int) Math.ceil((value / (value + 1.0F)));
}
/**
*
* scale
*
*
* @param value
* a double.
* @return a int.
*/
public static int scale(double value) {
return (Integer.MAX_VALUE - 2) * (int) Math.ceil((value / (value + 1.0)));
}
/**
*
* scale
*
*
* @param value
* a long.
* @return a int.
*/
public static int scale(long value) {
return (Integer.MAX_VALUE - 2) * (int) Math.ceil((value / (value + 1.0)));
}
public static int scaleTo(double value, int max) {
return (int) (Math.ceil(max * (1.0 * value / (value + 1.0))));
}
/**
*
* overflowDistance
*
*
* @param op1
* a int.
* @param op2
* a int.
* @param opcode
* a int.
* @return a int.
*/
public static int overflowDistance(int op1, int op2, int opcode) {
switch (opcode) {
case Opcodes.IADD:
int result = overflowDistanceAdd(op1, op2);
logger.debug("O: "+op1+" + "+op2+" = "+(op1+op2)+" -> "+result);
return result;
case Opcodes.ISUB:
return overflowDistanceSub(op1, op2);
case Opcodes.IMUL:
return overflowDistanceMul(op1, op2);
case Opcodes.IDIV:
return overflowDistanceDiv(op1, op2);
}
return Integer.MAX_VALUE;
}
protected final static int HALFWAY = Integer.MAX_VALUE / 2;
protected static int overflowDistanceAdd(int op1, int op2) {
int result = op1 + op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
if(result < 0)
return result;
else {
int retVal = HALFWAY - scaleTo(result, HALFWAY);
if(retVal != 0)
return retVal;
else
return 1;
}
} else if (op1 < 0 && op2 < 0) {
// if both are negative then both need to be increased
return HALFWAY
+ scaleTo(Math.abs((long) op1) + Math.abs((long) op2), HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceAdd(int op1, int op2) {
int result = op1 + op2;
if (op1 <= 0 && op2 <= 0) {
if(op1 == Integer.MIN_VALUE && op2 == Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
} else {
// result has to be < 0 for overflow
return result > 0 ? -result : HALFWAY
- scaleTo(Math.abs((long) result), HALFWAY) + 1;
}
} else if (op1 > 0 && op2 > 0) {
// if both are positive then both need to be decreased
return HALFWAY
+ scaleTo(Math.abs((long) op1) + Math.abs((long) op2), HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else {
// Unreachable
return Integer.MAX_VALUE;
}
}
protected static int overflowDistanceSub(int op1, int op2) {
int result = op1 - op2;
if (op1 >= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result < 0 ? result : HALFWAY + 1 - scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
// if both are negative then an overflow will be difficult
return HALFWAY
+ scaleTo(Math.abs((long) op1) + Math.abs((long) op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(op2, HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs((long) op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceSub(int op1, int op2) {
int result = op1 - op2;
if (op1 <= 0 && op2 >= 0) {
return result > 0 ? -result : HALFWAY + 1 - scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 < 0) {
return HALFWAY
+ scaleTo(Math.abs((long) op1) + Math.abs((long) op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(op1, HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs((long) op2), HALFWAY);
} else {
// Not sure if this can be reached
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int overflowDistanceMul(int op1, int op2) {
int result = op1 * op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
// the result can be so large that it overflows so much to be positive again
// so we need to use longs to check this
long longResult = (long)op1 * (long)(op2);
if(longResult > Integer.MAX_VALUE) {
if(result <= 0)
return result;
else
return Integer.MIN_VALUE;
}
else {
int retval = HALFWAY - scaleTo(result, HALFWAY);
if(retval > 0)
return retval;
else
return 1;
}
//System.out.println(op1+" * "+op2 +" -> "+result +" -> "+(HALFWAY - scaleTo(result, HALFWAY)));
//return result <= 0 ? result : HALFWAY - scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return result <= 0 ? result : HALFWAY - scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 < 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int underflowDistanceMul(int op1, int op2) {
int result = op1 * op2;
if (op1 > 0 && op2 < 0) {
return result >= 0 ? -result : HALFWAY - scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result >= 0 ? -result : HALFWAY - scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 > 0) {
return HALFWAY + scaleTo(Math.min(op1, op2), HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return HALFWAY + scaleTo(Math.abs(Math.max(op1, op2)), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int overflowDistanceDiv(int op1, int op2) {
if (op1 == Integer.MIN_VALUE && op2 == -1)
return -1;
else {
// If op2 is MAX_VALUE then -1 -op2 will give us an overflow
if(op2 == Integer.MAX_VALUE)
return Integer.MAX_VALUE;
// TODO There may be an overflow here
return scaleTo(Math.abs(Integer.MIN_VALUE - op1), HALFWAY)
+ scaleTo(Math.abs(-1 - op2), HALFWAY);
}
}
public static int underflowDistance(int op1, int op2, int opcode) {
switch (opcode) {
case Opcodes.IADD:
int result = underflowDistanceAdd(op1, op2);
logger.debug("U: "+op1+" + "+op2+" = "+(op1+op2)+" -> "+result);
return result;
case Opcodes.ISUB:
return underflowDistanceSub(op1, op2);
case Opcodes.IMUL:
return underflowDistanceMul(op1, op2);
}
return Integer.MAX_VALUE;
}
public static int overflowDistance(float op1, float op2, int opcode) {
switch (opcode) {
case Opcodes.FADD:
return overflowDistanceAdd(op1, op2);
case Opcodes.FSUB:
return overflowDistanceSub(op1, op2);
case Opcodes.FMUL:
return overflowDistanceMul(op1, op2);
case Opcodes.FDIV:
return overflowDistanceDiv(op1, op2);
}
return Integer.MAX_VALUE;
}
public static int underflowDistance(float op1, float op2, int opcode) {
switch (opcode) {
case Opcodes.FADD:
return underflowDistanceAdd(op1, op2);
case Opcodes.FSUB:
return underflowDistanceSub(op1, op2);
case Opcodes.FMUL:
return underflowDistanceMul(op1, op2);
}
return Integer.MAX_VALUE;
}
protected static int overflowDistanceAdd(float op1, float op2) {
float result = op1 + op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
return result == Float.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 < 0 && op2 < 0) {
// if both are negative then both need to be increased
return result == Float.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo((double) op1 + (double) op2, HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceAdd(float op1, float op2) {
float result = op1 + op2;
if (op1 <= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result == Float.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(Math.abs((double) result), HALFWAY) + 1;
} else if (op1 > 0 && op2 > 0) {
// if both are positive then both need to be decreased
return result == Float.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs((double) op1) + Math.abs((double) op2), HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
return HALFWAY + scaleTo(op1, HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
return HALFWAY + scaleTo(op2, HALFWAY);
} else {
// Unreachable
return Integer.MAX_VALUE;
}
}
protected static int overflowDistanceSub(float op1, float op2) {
float result = op1 - op2;
if (op1 >= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result == Float.POSITIVE_INFINITY ? -1 : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
// if both are negative then an overflow will be difficult
return result == Float.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs((double) op1) + Math.abs((double) op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(op2, HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs((double) op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceSub(float op1, float op2) {
float result = op1 - op2;
if (op1 <= 0 && op2 >= 0) {
return result == Float.NEGATIVE_INFINITY ? -1 : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 < 0) {
return result == Float.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs((double) op1) + Math.abs((double) op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(Math.abs((double) op1), HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs((double) op2), HALFWAY);
} else {
// Not sure if this can be reached
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int overflowDistanceMul(float op1, float op2) {
float result = op1 * op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
return result == Float.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return result == Float.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 > 0 && op2 < 0) {
// In this case we can't have an overflow yet
return result == Float.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result == Float.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int underflowDistanceMul(float op1, float op2) {
float result = op1 * op2;
if (op1 > 0 && op2 < 0) {
return result == Float.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result == Float.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 > 0) {
return result == Float.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.min(op1, op2), HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return result == Float.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(Math.max(op1, op2)), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int overflowDistanceDiv(float op1, float op2) {
if (op1 == -Float.MAX_VALUE && op2 == -1.0)
return -1;
else
// TODO There may be an overflow here
return scaleTo(Math.abs(-Float.MAX_VALUE - op1), HALFWAY)
+ scaleTo(Math.abs(-1.0 - op2), HALFWAY);
}
public static int overflowDistance(double op1, double op2, int opcode) {
switch (opcode) {
case Opcodes.DADD:
return overflowDistanceAdd(op1, op2);
case Opcodes.DSUB:
return overflowDistanceSub(op1, op2);
case Opcodes.DMUL:
return overflowDistanceMul(op1, op2);
case Opcodes.DDIV:
return overflowDistanceDiv(op1, op2);
}
return Integer.MAX_VALUE;
}
public static int underflowDistance(double op1, double op2, int opcode) {
switch (opcode) {
case Opcodes.DADD:
return underflowDistanceAdd(op1, op2);
case Opcodes.DSUB:
return underflowDistanceSub(op1, op2);
case Opcodes.DMUL:
return underflowDistanceMul(op1, op2);
}
return Integer.MAX_VALUE;
}
protected static int overflowDistanceAdd(double op1, double op2) {
double result = op1 + op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
return result == Double.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 < 0 && op2 < 0) {
return result == Double.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 >= 0 && op2 < 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceAdd(double op1, double op2) {
double result = op1 + op2;
if (op1 <= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result == Double.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(Math.abs(result), HALFWAY) + 1;
} else if (op1 > 0 && op2 > 0) {
// if both are positive then both need to be decreased
return result == Double.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
return HALFWAY + scaleTo(op1, HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
return HALFWAY + scaleTo(op2, HALFWAY);
} else {
// Unreachable
return Integer.MAX_VALUE;
}
}
protected static int overflowDistanceSub(double op1, double op2) {
double result = op1 - op2;
if (op1 >= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result == Double.POSITIVE_INFINITY ? -1 : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
// if both are negative then an overflow will be difficult
return result == Double.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(op2, HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceSub(double op1, double op2) {
double result = op1 - op2;
if (op1 <= 0 && op2 >= 0) {
return result == Double.NEGATIVE_INFINITY ? -1 : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 < 0) {
return result == Double.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else {
// Not sure if this can be reached
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int overflowDistanceMul(double op1, double op2) {
double result = op1 * op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
return result == Double.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return result == Double.POSITIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 > 0 && op2 < 0) {
// In this case we can't have an overflow yet
return result == Double.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result == Double.NEGATIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int underflowDistanceMul(double op1, double op2) {
double result = op1 * op2;
if (op1 > 0 && op2 < 0) {
return result == Double.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result == Double.NEGATIVE_INFINITY ? -1 : HALFWAY
- scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 > 0) {
return result == Double.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.min(op1, op2), HALFWAY);
} else if (op1 < 0 && op2 < 0) {
return result == Double.POSITIVE_INFINITY ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(Math.max(op1, op2)), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int overflowDistanceDiv(double op1, double op2) {
if (op1 == -Double.MAX_VALUE && op2 == -1.0)
return -1;
else
// TODO There may be an overflow here
return scaleTo(Math.abs(-Double.MAX_VALUE - op1), HALFWAY)
+ scaleTo(Math.abs(-1.0 - op2), HALFWAY);
}
public static int overflowDistance(long op1, long op2, int opcode) {
switch (opcode) {
case Opcodes.LADD:
return overflowDistanceAdd(op1, op2);
case Opcodes.LSUB:
return overflowDistanceSub(op1, op2);
case Opcodes.LMUL:
return overflowDistanceMul(op1, op2);
case Opcodes.LDIV:
return overflowDistanceDiv(op1, op2);
}
return Integer.MAX_VALUE;
}
public static int underflowDistance(long op1, long op2, int opcode) {
switch (opcode) {
case Opcodes.LADD:
return underflowDistanceAdd(op1, op2);
case Opcodes.LSUB:
return underflowDistanceSub(op1, op2);
case Opcodes.LMUL:
return underflowDistanceMul(op1, op2);
}
return Integer.MAX_VALUE;
}
protected static int overflowDistanceAdd(long op1, long op2) {
long result = op1 + op2;
if (op1 > 0 && op2 > 0) {
// result has to be < 0 for overflow
return result < 0 ? -scaleTo(Math.abs(result), HALFWAY) : HALFWAY
- scaleTo(result, HALFWAY) + 1;
} else if (op1 < 0 && op2 < 0) {
return result > 0 ? Integer.MAX_VALUE : HALFWAY - scaleTo(result, HALFWAY)
+ 1;
} else if (op1 >= 0 && op2 < 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
// If only one is negative, then optimize that to be positive
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceAdd(long op1, long op2) {
long result = op1 + op2;
if (op1 <= 0L && op2 <= 0L) {
// result has to be < 0 for underflow
if(result > 0) {
int retval = -scaleTo(result, HALFWAY);
if(retval < 0)
return retval;
else
return -1;
} else if(result == 0L) {
if(op1 != 0 && op2 != 0) {
return -1;
} else {
return HALFWAY
- scaleTo(Math.abs(result), HALFWAY);
}
} else {
int intResult = HALFWAY
- scaleTo(Math.abs(result), HALFWAY);
if(intResult == 0)
return 1;
else
return intResult;
}
} else if (op1 > 0 && op2 > 0) {
// if both are positive then both need to be decreased
return result < 0 ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 < 0) {
return HALFWAY + scaleTo(op1, HALFWAY);
} else if (op1 < 0 && op2 >= 0) {
return HALFWAY + scaleTo(op2, HALFWAY);
} else {
// Unreachable
return Integer.MAX_VALUE;
}
}
protected static int overflowDistanceSub(long op1, long op2) {
long result = op1 - op2;
if (op1 >= 0 && op2 <= 0) {
// result has to be < 0 for overflow
return result < 0 ? -scaleTo(Math.abs(result), HALFWAY) : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 < 0 && op2 > 0) {
// if both are negative then an overflow will be difficult
return result > 0 ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(op2, HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else {
// At least one of them is zero, and the sum is larger or equals than 0
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int underflowDistanceSub(long op1, long op2) {
long result = op1 - op2;
if (op1 <= 0 && op2 >= 0) {
return result > 0 ? -scaleTo(result, HALFWAY) : HALFWAY + 1
- scaleTo(result, HALFWAY);
} else if (op1 > 0 && op2 < 0) {
return result < 0 ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1) + Math.abs(op2), HALFWAY);
} else if (op1 >= 0 && op2 > 0) {
// In this case we can't have an overflow yet
return HALFWAY + scaleTo(Math.abs(op1), HALFWAY);
} else if (op1 < 0 && op2 <= 0) {
return 1 + HALFWAY + scaleTo(Math.abs(op2), HALFWAY);
} else {
// Not sure if this can be reached
return 1 + HALFWAY - scaleTo(result, HALFWAY);
}
}
protected static int overflowDistanceMul(long op1, long op2) {
long result = op1 * op2;
if ((op1 > 0 && op2 > 0) || (op1 < 0 && op2 < 0)) {
BigDecimal bigDecimal = new BigDecimal(op1).multiply(new BigDecimal(op2));
BigDecimal maxResult = new BigDecimal(Long.MAX_VALUE);
if(bigDecimal.compareTo(maxResult) > 0) {
int intResult = -scaleTo(Math.abs(result), HALFWAY);
if(result <= 0)
return intResult;
else
return Integer.MIN_VALUE;
}
else {
int retval = HALFWAY - scaleTo(result, HALFWAY);
if(retval > 0)
return retval;
else
return 1;
}
// result has to be < 0 for overflow
} else if (op1 > 0 && op2 < 0) {
// In this case we can't have an overflow yet
return result > 0 ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op2), HALFWAY);
} else if (op1 < 0 && op2 > 0) {
return result > 0 ? Integer.MAX_VALUE : HALFWAY
+ scaleTo(Math.abs(op1), HALFWAY);
} else {
// One of them is zero
return HALFWAY;
}
}
protected static int underflowDistanceMul(long op1, long op2) {
long result = op1 * op2;
BigDecimal bigDecimal = new BigDecimal(op1).multiply(new BigDecimal(op2));
BigDecimal minResult = new BigDecimal(Long.MIN_VALUE);
if(bigDecimal.compareTo(minResult) < 0) {
int intResult = -scaleTo(Math.abs(result), HALFWAY);
if(result <= 0)
return intResult;
else
return Integer.MIN_VALUE;
}
else {
int retval = HALFWAY - scaleTo(result, HALFWAY);
if(retval > 0)
return retval;
else
return 1;
}
}
protected static int overflowDistanceDiv(long op1, long op2) {
if (op1 == Long.MIN_VALUE && op2 == -1L)
return -1;
else
// TODO There may be an overflow here
return scaleTo(Math.abs(Long.MIN_VALUE - op1), HALFWAY)
+ scaleTo(Math.abs(-1L - op2), HALFWAY);
}
}