diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java b/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java index aa2ad9620fe..b49c841fe29 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultOperations.java @@ -32,21 +32,44 @@ public class DefaultOperations { static { // Number - Number Arithmetics.registerOperation(Operator.ADDITION, Number.class, (left, right) -> { - double result = left.doubleValue() + right.doubleValue(); - if (Utils.isInteger(left, right) && result < Long.MAX_VALUE && result > Long.MIN_VALUE) - return (long) result; - return result; + if (Utils.isInteger(left, right)) { + long result = left.longValue() + right.longValue(); + // catches overflow, from Math.addExact(long, long) + if (((left.longValue() ^ result) & (right.longValue() ^ result)) >= 0) + return (result); + } + return left.doubleValue() + right.doubleValue(); }); Arithmetics.registerOperation(Operator.SUBTRACTION, Number.class, (left, right) -> { - double result = left.doubleValue() - right.doubleValue(); - if (Utils.isInteger(left, right) && result < Long.MAX_VALUE && result > Long.MIN_VALUE) - return (long) result; - return result; + if (Utils.isInteger(left, right)) { + long result = left.longValue() - right.longValue(); + // catches overflow, from Math.addExact(long, long) + if (((left.longValue() ^ result) & (right.longValue() ^ result)) >= 0) + return (result); + } + return left.doubleValue() - right.doubleValue(); }); Arithmetics.registerOperation(Operator.MULTIPLICATION, Number.class, (left, right) -> { - double result = left.doubleValue() * right.doubleValue(); - if (Utils.isInteger(left, right) && result < Long.MAX_VALUE && result > Long.MIN_VALUE) - return (long) result; + if (!Utils.isInteger(left, right)) + return left.doubleValue() * right.doubleValue(); + + // catch overflow, from Math.multiplyExact(long, long) + long longLeft = left.longValue(); + long longRight = right.longValue(); + long ax = Math.abs(longLeft); + long ay = Math.abs(longRight); + + long result = left.longValue() * right.longValue(); + + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((longRight != 0) && (result / longRight != longLeft)) || + (longLeft == Long.MIN_VALUE && longRight == -1)) { + return left.doubleValue() * right.doubleValue(); + } + } return result; }); Arithmetics.registerOperation(Operator.DIVISION, Number.class, (left, right) -> left.doubleValue() / right.doubleValue());