This question already has answers here:
Why is Java's Double.compare(double, double) implemented the way it is?
(4 answers)
Closed 1 year ago.
i heared that i should use compare() method for comparing two objects.
instead of using - (substraction) directly. because -(substraction) can invoke overflow
public class Employee implements Comparable<Employee> {
...
public int compareTo(Employee other) {
return Double.compare(salary, other.salary); // don't use (-)
}
}
and when i saw this implemented CompareTo() code(in Interger.class)
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
and i could see '>'
but as i know it eventually would be using substraction like in c++... probably in interpreter.. if i'm right
and use this result 0 ,1,-1 as = < >
what's different?
why when i use compareTo() method i can avoid overflowing?
please give me a detail reason.
As said in this post, the problem with using subtraction is the following.
This is due to integer overflow. When thisVal is very large and anotherVal is negative then subtracting the latter from the former yields a result that is bigger than thisVal which may overflow to the negative range.
https://stackoverflow.com/a/2728810/9520059
Indeed, the compiler will probably use a subtraction at very low level when evaluating the '<', however, it will check for overflows.
Related
This question already has answers here:
How can I check if multiplying two numbers in Java will cause an overflow?
(15 answers)
Closed 4 years ago.
int a = 200000;
double b = (double) (a*a);
I would like to be able to calculate if (aa) (integers) is already too large (stackOverflow) to hold in the variable; in this case I know that multiplying (aa) leads to an int that will not fit -> the number will be wrong;
What I do not understand is how I can calculate this off the top of my head. How can I see if a value will not fit in an int variable??
Is there a way to do this without using methods, by just using the plain code and common sense? ;-)
Best regards,
Wouter
Two possible solutions.
Catch exception thrown after a call to the Math.…Exact methods: Math.multiplyExact, Math.addExact, Math.decrementExact, and so on.
int a = 200000;
try {
int result = Math.multiplyExact(x, y);
} catch(ArithmeticException e) {
//if you get here, it is too big
}
Or, check against the constants for minimum and maximum possible integer values.
long test = (long)a*(long)a;
if (test > Integer.MAX_VALUE || test < Integer.MIN_VALUE)
// Overflow!
You could make use of the constant MAX_VALUE from the Integer wrapper class and cast to long instead (you will get a compile error if you cast to double but exceed it's range)
int a = 200000;
long b = (long) a * (long) a;
if (b > Integer.MAX_VALUE) {
// do something
}
MAX_VALUE corresponds to the highest value an integer can be, (2^31)-1
This question already has answers here:
Multiplication of two ints overflowing to result in a negative number
(5 answers)
Closed 9 years ago.
static int fn = 0;
static int sn = 0;
static boolean running = false;
public static void run()
{
while (running == true)
{
fn = numbers[0];
sn = numbers[1];
if (sign == 0)
{
input.setText(String.valueOf(fn));
}
}
}
static class one implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (Display.sign == 0)
{
Display.numbers[0] = Display.numbers[0] *10;
Display.numbers[0] = Display.numbers[0] +1;
}
}
}
This is the code for a calculator that I am programming (not all of it of course). This is the part where I display the number on the screen which I have done, but weirdly this works up until 10 characters
So after I get the program to display 1111111111 I want to do it once more and it gives me this weird number -1773790777. I am confused about how the program comes up with this. As you can see, above Display.numbers[] is the array I am storing the two numbers in. So to go over a place I multiply the number in the array by 10 then add 1. So how does this give me a negative number in the first place and what can I do to solve this problem?
Is your number overflowing?
You can check it by looking at Integer.MAX_VALUE (assuming you are using an integer). If you go over that you will loop will get weird results like this. See - http://javapapers.com/core-java/java-overflow-and-underflow/ for more details.
It's overflowing!
1111111111*10 + 1 = 11111111111 which is 0x2964619C7 in hexadecimal. It's a 34-bit value which can't be stored in a 32-bit int
In Java arithmetic operations wrap around by default, so if the result overflowed then it'll be wrapped back to the other end of the value range. See How does Java handle integer underflows and overflows and how would you check for it?
However due to the use of 2's complement, the result will be the lower bits of the result 11111111111 mod 232 = 2521176519 = 0x964619C7 which is -1'773'790'777 in 32-bit int, that's why you see the number. You should read more on binary, that's the basic of nowadays computers
In Java 8 you'll have an easier way to detect overflow with the new *Exact methods
The platform uses signed two's complement integer arithmetic with int and long primitive types. The developer should choose the primitive type to ensure that arithmetic operations consistently produce correct results, which in some cases means the operations will not overflow the range of values of the computation. The best practice is to choose the primitive type and algorithm to avoid overflow. In cases where the size is int or long and overflow errors need to be detected, the methods addExact, subtractExact, multiplyExact, and toIntExact throw an ArithmeticException when the results overflow. For other arithmetic operations such as divide, absolute value, increment, decrement, and negation overflow occurs only with a specific minimum or maximum value and should be checked against the minimum or maximum as appropriate.
https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html
I am studying the source of the OpenJDK.
My attention was attracted by the methods Byte.compare() and Integer.compare():
public static int Byte.compare(byte x, byte y) {
return x-y;
}
public static int Integer.compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
Why do the methods Byte.compare() and Integer.compare() have different implementations?
The implementation of Integer.compare does not use subtraction, as this could cause an overflow in case you're comparing an integer that is close to Integer.MIN_VALUE with another that is close to Integer.MAX_VALUE.
This overflow cannot happen in case of Byte.compare, as there the byte values are implicitely converted to integers before x-y is calculated.
(see also: Java Language Specification - 5.6.2 Binary Numeric Promotion)
The Byte method can be implemented this way, becasue the result of the subtraction is representable in int. This is not so in the other case. For example:
0 - 0x80000000 == 0x80000000
and this is negative, hence the comparision would wrongly indicate that 0 is smaller than -2^31
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I check if multiplying two numbers in Java will cause an overflow?
Suppose I have a Java class method, which uses * and + operations.
int foo(int a, int b) {
... // some calculations with + and *
}
How to make sure that no overflow occurs in foo?
I guess I can either use BigDecimal or replace all + and * with "wrappers" like:
int sum(int a, int b) {
int c = a + b;
if (a > 0 && b > 0 && c < 0)
throw new MyOverfowException(a, b)
return c;
}
int prod(int a, int b) {
int c = a * b;
if (a > 0 && b > 0 && c < 0)
throw new MyOverfowException(a, b)
return c;
}
Are there better ways to make sure that no int overflow occurs in a Java method ?
One way to check for an overflow is to have the operands promoted to a larger type (of double the original operand bit length) then perform the operation, and then see if the resulting value is too large for the original type, e.g.
int sum(int a, int b) {
long r = (long)a + b;
if (r >>> 32 != 0) { // no sign extension
throw new MyOverflowException(a, b);
}
return (int)r;
}
If your original type is a long, you'd have to use BigInteger as that larger type.
It is a difficult problem from an engineering perspective.
The Secure Coding site recommends:
use of preconditions; i.e. range-check the inputs so that overflow is impossible,
doing each individual arithmetic operation using the next larger primitive integer type and explicitly checking for overflow, or
using BigInteger.
This Dr Dobbs article suggests creating a library of primitive arithmetic methods that do each primitive operation with an explicit overflow check. (You could view this as an implementation of bullet point #2 above.) But the authors go further by suggesting that you use bytecode rewriting to replace arithmetic bytecodes with calls to the equivalent methods which incorporate overflow checks.
Unfortunately, there is no way to enable overflow checking natively in Java. (But the same applies in lots of other languages; e.g. C, C++ ... )
Sum: Check whether b is larger than the difference of the maximum value you can store in int minus the value of a. If a and/or b can be negative, you must (i) be careful not to get an overflow already for the difference check and (ii) perform a similar check for the minimum.
Product: Thats more difficult. I would split the integers into two half-length integers (i.e. if int is 32 bit, split it into two 16 bit numbers using bit-masking and shifting). Then do the multiplication, and then look whether the result fits into 32 bit.
Everything under the condition that you do not want to simply take long for the temporary result.
Suppose both a and b are positive or negative, and if the sign of a + b is not equal with the sign of a and b, then overflow happens. You can use this rule to judge whether overflow happens and throw an exception. When you catch this expcetion, you can deal it according to the method metioned in previous answers.
Another method is to doing operation using largest range type which will not overflow. You can use long for the operation between Integers.
java.lang.Comparable#compareTo method states as first provision
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compare-
To(x)) for all x and y. (This implies that x.compareTo(y) must throw
an exception if and only if y.compareTo(x) throws an exception.)
and according Joshua Bloch in Effective Java in item 12
This trick works fine here but should be used with extreme caution.
Don’t use it unless you’re certain the fields in question are
non-negative or, more generally, that the difference between the
lowest and highest possible field values is less than or equal to
Integer.MAX_VALUE (231-1). The reason this trick doesn’t always work
is that a signed 32-bit integer isn’t big enough to hold the
difference between two arbitrary signed 32-bit integers. If i is a
large positive int and j is a large negative int, (i - j) will
overflow and return a negative value. The resulting compareTo method
will return incorrect results for some arguments and violate the first
and second provisions of the compareTo contract. This is not a purely
theoretical problem: it has caused failures in real systems. These
failures can be difficult to debug, as the broken compareTo method
works properly for most input values.
With integers overflow you can violate the first provision and I can't find how, this example shows how the first provision would be violated:
public class ProblemsWithLargeIntegers implements Comparable<ProblemsWithLargeIntegers> {
private int zas;
#Override
public int compareTo(ProblemsWithLargeIntegers o) {
return zas - o.zas;
}
public ProblemsWithLargeIntegers(int zas) {
this.zas = zas;
}
public static void main(String[] args) {
int value1 = ...;
int value2 = ...;
ProblemsWithLargeIntegers d = new ProblemsWithLargeIntegers(value1);
ProblemsWithLargeIntegers e = new ProblemsWithLargeIntegers(value2);
if (!(Math.signum(d.compareTo(e)) == -Math.signum(e.compareTo(d)))){
System.out.println("hey!");
}
}
So I want a value1 and a value2 for getting that? Any idea? Or Joshua was wrong?
Well, this violates the general contract to start with. For example, take value1 = Integer.MIN_VALUE and value2 = 1. That will report that Integer.MIN_VALUE > 1, effectively.
EDIT: Actually, I was wrong - it's easy to violate the first provision:
int value1 = Integer.MIN_VALUE;
int value2 = 0;
You'll get a negative result for both comparisons, because Integer.MIN_VALUE - 0 == 0 - Integer.MIN_VALUE.