Skip to content

Commit

Permalink
don't compromise with precision
Browse files Browse the repository at this point in the history
uses Math.xExact code to catch overflows instead of relying on doubles.
  • Loading branch information
sovdeeth committed Nov 10, 2024
1 parent 87cc25d commit 771b09a
Showing 1 changed file with 34 additions and 11 deletions.
45 changes: 34 additions & 11 deletions src/main/java/ch/njol/skript/classes/data/DefaultOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down

0 comments on commit 771b09a

Please sign in to comment.