How to use comparison operators like >, =, < on BigDecimal - java

I have a domain class with unitPrice set as BigDecimal data type. Now I am trying to create a method to compare price but it seems like I can't have comparison operators in BigDecimal data type. Do I have to change data type or is there other way around?

To be short:
firstBigDecimal.compareTo(secondBigDecimal) < 0 // "<"
firstBigDecimal.compareTo(secondBigDecimal) > 0 // ">"
firstBigDecimal.compareTo(secondBigDecimal) == 0 // "=="
firstBigDecimal.compareTo(secondBigDecimal) >= 0 // ">="

Every object of the Class BigDecimal has a method compareTo you can use to compare it to another BigDecimal. The result of compareTo is then compared > 0, == 0 or < 0 depending on what you need. Read the documentation and you will find out.
The operators ==, <, > and so on can only be used on primitive data types like int, long, double or their wrapper classes like Integerand Double.
From the documentation of compareTo:
Compares this BigDecimal with the specified BigDecimal.
Two BigDecimal
objects that are equal in value but have a different scale (like 2.0
and 2.00) are considered equal by this method. This method is provided
in preference to individual methods for each of the six boolean
comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for
performing these comparisons is: (x.compareTo(y) <op> 0), where <op>
is one of the six comparison operators.
Returns:
-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.

Use the compareTo method of BigDecimal :
public int compareTo(BigDecimal val) Compares this BigDecimal with the
specified BigDecimal.
Returns:
-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.

Here is an example for all six boolean comparison operators (<, ==, >, >=, !=, <=):
BigDecimal big10 = new BigDecimal(10);
BigDecimal big20 = new BigDecimal(20);
System.out.println(big10.compareTo(big20) < -1); // false
System.out.println(big10.compareTo(big20) <= -1); // true
System.out.println(big10.compareTo(big20) == -1); // true
System.out.println(big10.compareTo(big20) >= -1); // true
System.out.println(big10.compareTo(big20) > -1); // false
System.out.println(big10.compareTo(big20) != -1); // false
System.out.println(big10.compareTo(big20) < 0); // true
System.out.println(big10.compareTo(big20) <= 0); // true
System.out.println(big10.compareTo(big20) == 0); // false
System.out.println(big10.compareTo(big20) >= 0); // false
System.out.println(big10.compareTo(big20) > 0); // false
System.out.println(big10.compareTo(big20) != 0); // true
System.out.println(big10.compareTo(big20) < 1); // true
System.out.println(big10.compareTo(big20) <= 1); // true
System.out.println(big10.compareTo(big20) == 1); // false
System.out.println(big10.compareTo(big20) >= 1); // false
System.out.println(big10.compareTo(big20) > 1); // false
System.out.println(big10.compareTo(big20) != 1); // true

You can use method named compareTo, x.compareTo(y). It will return 0 if x and y are equal, 1 if x is greater than y and -1 if x is smaller than y

Discussion
This thread has plenty of answers stating that the BigDecimal.compareTo(BigDecimal) method is the one to use to compare BigDecimal instances. I just wanted to add for anyone not experienced with using the BigDecimal.compareTo(BigDecimal) method: Be careful with how you create your BigDecimal instances. For example:
new BigDecimal(0.8) will create a BigDecimal instance with a value which is not exactly 0.8 and which has a scale of 50+,
new BigDecimal("0.8") will create a BigDecimal instance with a value which is exactly 0.8 and which has a scale of 1.
These two BigDecimal instances are unequal according to the BigDecimal.compareTo(BigDecimal) method because their values are unequal when the scale is not limited to a few decimal places.
Summary
Firstly, be careful to create your BigDecimal instances with the BigDecimal(String val) constructor or the BigDecimal.valueOf(double val) method rather than the BigDecimal(double val) constructor. Secondly, note that you can limit the scale of BigDecimal instances prior to comparing them by means of the BigDecimal.setScale(int newScale, RoundingMode roundingMode) method.

BigDecimal isn't a primitive, so you cannot use the <, > operators. However, since it's a Comparable, you can use the compareTo(BigDecimal) to the same effect. E.g.:
public class Domain {
private BigDecimal unitPrice;
public boolean isCheaperThan(BigDecimal other) {
return unitPirce.compareTo(other.unitPrice) < 0;
}
// etc...
}

Alternatively, if you're already using commons-lang3 (version 3.10 and up), you can leverage their ComparableUtils API like so:
import static org.apache.commons.lang3.compare.ComparableUtils.is;
var areEqual = is(first).equalTo(second);
var isGreater = is(first).greaterThan(second);
var isLess = is(first).lessThan(second);
var isBetween = is(first).between(second, third);
// etc.
Nowadays, most large projects include commons-lang3 as a dependency, anyway.

You can follow this utility static method and Operator enum for comparing the two numbers:
public static boolean check(BigDecimal firstNum, Operator operator, BigDecimal secondNum) {
switch (operator) {
case EQUALS:
return firstNum.compareTo(secondNum) == 0;
case LESS_THAN:
return firstNum.compareTo(secondNum) < 0;
case LESS_THAN_OR_EQUALS:
return firstNum.compareTo(secondNum) <= 0;
case GREATER_THAN:
return firstNum.compareTo(secondNum) > 0;
case GREATER_THAN_OR_EQUALS:
return firstNum.compareTo(secondNum) >= 0;
}
throw new IllegalArgumentException("Will never reach here");
}
public enum Operator {
LESS_THAN, LESS_THAN_OR_EQUALS, GREATER_THAN, GREATER_THAN_OR_EQUALS, EQUALS
}

Using com.ibm.etools.marshall.util.BigDecimalRange util class of IBM one can compare if BigDecimal in range.
boolean isCalculatedSumInRange = BigDecimalRange.isInRange(low, high, calculatedSum);

Below is an example to compare two BigDecimal values.
public class BigDecimalDemo {
public static void main(String[] args) {
// create 2 BigDecimal objects
BigDecimal bg1, bg2;
bg1 = new BigDecimal("10");
bg2 = new BigDecimal("20");
//create int object
int res;
res = bg1.compareTo(bg2); // compare bg1 with bg2
String str1 = "Both values are equal ";
String str2 = "First Value is greater ";
String str3 = "Second value is greater";
if( res == 0 )
System.out.println( str1 );
else if( res == 1 )
System.out.println( str2 );
else if( res == -1 )
System.out.println( str3 );
}
}

Related

Why is this HackerRank problem working fine with 'int' but not with 'Integer'? [duplicate]

I know that if you compare a boxed primitive Integer with a constant such as:
Integer a = 4;
if (a < 5)
a will automatically be unboxed and the comparison will work.
However, what happens when you are comparing two boxed Integers and want to compare either equality or less than/greater than?
Integer a = 4;
Integer b = 5;
if (a == b)
Will the above code result in checking to see if they are the same object, or will it auto-unbox in that case?
What about:
Integer a = 4;
Integer b = 5;
if (a < b)
?
No, == between Integer, Long etc will check for reference equality - i.e.
Integer x = ...;
Integer y = ...;
System.out.println(x == y);
this will check whether x and y refer to the same object rather than equal objects.
So
Integer x = new Integer(10);
Integer y = new Integer(10);
System.out.println(x == y);
is guaranteed to print false. Interning of "small" autoboxed values can lead to tricky results:
Integer x = 10;
Integer y = 10;
System.out.println(x == y);
This will print true, due to the rules of boxing (JLS section 5.1.7). It's still reference equality being used, but the references genuinely are equal.
If the value p being boxed is an integer literal of type int between
-128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f'
inclusive (§3.10.4), then let a and b be the results of any two boxing
conversions of p. It is always the case that a == b.
Personally I'd use:
if (x.intValue() == y.intValue())
or
if (x.equals(y))
As you say, for any comparison between a wrapper type (Integer, Long etc) and a numeric type (int, long etc) the wrapper type value is unboxed and the test is applied to the primitive values involved.
This occurs as part of binary numeric promotion (JLS section 5.6.2). Look at each individual operator's documentation to see whether it's applied. For example, from the docs for == and != (JLS 15.21.1):
If the operands of an equality
operator are both of numeric type, or
one is of numeric type and the other
is convertible (§5.1.8) to numeric
type, binary numeric promotion is
performed on the operands (§5.6.2).
and for <, <=, > and >= (JLS 15.20.1)
The type of each of the operands of a
numerical comparison operator must be
a type that is convertible (§5.1.8) to
a primitive numeric type, or a
compile-time error occurs. Binary
numeric promotion is performed on the
operands (§5.6.2). If the promoted
type of the operands is int or long,
then signed integer comparison is
performed; if this promoted type is
float or double, then floating-point
comparison is performed.
Note how none of this is considered as part of the situation where neither type is a numeric type.
== will still test object equality. It is easy to be fooled, however:
Integer a = 10;
Integer b = 10;
System.out.println(a == b); //prints true
Integer c = new Integer(10);
Integer d = new Integer(10);
System.out.println(c == d); //prints false
Your examples with inequalities will work since they are not defined on Objects. However, with the == comparison, object equality will still be checked. In this case, when you initialize the objects from a boxed primitive, the same object is used (for both a and b). This is an okay optimization since the primitive box classes are immutable.
Since Java 1.7 you can use Objects.equals:
java.util.Objects.equals(oneInteger, anotherInteger);
Returns true if the arguments are equal to each other and false
otherwise. Consequently, if both arguments are null, true is returned
and if exactly one argument is null, false is returned. Otherwise,
equality is determined by using the equals method of the first
argument.
We should always go for the equals() method for comparison of two integers. It's the recommended practice.
If we compare two integers using == that would work for certain range of integer values (Integer from -128 to 127) due to the JVM's internal optimisation.
Please see examples:
Case 1:
Integer a = 100;
Integer b = 100;
if (a == b) {
System.out.println("a and b are equal");
} else {
System.out.println("a and b are not equal");
}
In above case JVM uses value of a and b from cached pool and return the same object instance(therefore memory address) of integer object and we get both are equal.Its an optimisation JVM does for certain range values.
Case 2: In this case, a and b are not equal because it does not come with the range from -128 to 127.
Integer a = 220;
Integer b = 220;
if (a == b) {
System.out.println("a and b are equal");
} else {
System.out.println("a and b are not equal");
}
Proper way:
Integer a = 200;
Integer b = 200;
System.out.println("a == b? " + a.equals(b)); // true
tl;dr my opinion is to use a unary + to trigger the unboxing on one of the operands when checking for value equality, and simply use the maths operators otherwise. Rationale follows:
It has been mentioned already that == comparison for Integer is identity comparison, which is usually not what a programmer want, and that the aim is to do value comparison; still, I've done a little science about how to do that comparison most efficiently, both in term of code compactness, correctness and speed.
I used the usual bunch of methods:
public boolean method1() {
Integer i1 = 7, i2 = 5;
return i1.equals( i2 );
}
public boolean method2() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2.intValue();
}
public boolean method3() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2;
}
public boolean method4() {
Integer i1 = 7, i2 = 5;
return i1 == +i2;
}
public boolean method5() { // obviously not what we want..
Integer i1 = 7, i2 = 5;
return i1 == i2;
}
and got this code after compilation and decompilation:
public boolean method1() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
return var1.equals( var2 );
}
public boolean method2() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method3() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method4() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method5() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2 == var1 ) {
return true;
} else {
return false;
}
}
As you can easily see, method 1 calls Integer.equals() (obviously), methods 2-4 result in exactly the same code, unwrapping the values by means of .intValue() and then comparing them directly, and method 5 just triggers an identity comparison, being the incorrect way to compare values.
Since (as already mentioned by e.g. JS) equals() incurs an overhead (it has to do instanceof and an unchecked cast), methods 2-4 will work with exactly the same speed, noticingly better than method 1 when used in tight loops, since HotSpot is not likely to optimize out the casts & instanceof.
It's quite similar with other comparison operators (e.g. </>) - they will trigger unboxing, while using compareTo() won't - but this time, the operation is highly optimizable by HS since intValue() is just a getter method (prime candidate to being optimized out).
In my opinion, the seldom used version 4 is the most concise way - every seasoned C/Java developer knows that unary plus is in most cases equal to cast to int/.intValue() - while it may be a little WTF moment for some (mostly those who didn't use unary plus in their lifetime), it arguably shows the intent most clearly and most tersely - it shows that we want an int value of one of the operands, forcing the other value to unbox as well. It is also unarguably most similar to the regular i1 == i2 comparison used for primitive int values.
My vote goes for i1 == +i2 & i1 > i2 style for Integer objects, both for performance & consistency reasons. It also makes the code portable to primitives without changing anything other than the type declaration. Using named methods seems like introducing semantic noise to me, similar to the much-criticized bigInt.add(10).multiply(-3) style.
== checks for reference equality, however when writing code like:
Integer a = 1;
Integer b = 1;
Java is smart enough to reuse the same immutable for a and b, so this is true: a == b. Curious, I wrote a small example to show where java stops optimizing in this way:
public class BoxingLol {
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Integer a = i;
Integer b = i;
if (a != b) {
System.out.println("Done: " + i);
System.exit(0);
}
}
System.out.println("Done, all values equal");
}
}
When I compile and run this (on my machine), I get:
Done: 128
Calling
if (a == b)
Will work most of the time, but it's not guaranteed to always work, so do not use it.
The most proper way to compare two Integer classes for equality, assuming they are named 'a' and 'b' is to call:
if(a != null && a.equals(b)) {
System.out.println("They are equal");
}
You can also use this way which is slightly faster.
if(a != null && b != null && (a.intValue() == b.intValue())) {
System.out.println("They are equal");
}
On my machine 99 billion operations took 47 seconds using the first method, and 46 seconds using the second method. You would need to be comparing billions of values to see any difference.
Note that 'a' may be null since it's an Object. Comparing in this way will not cause a null pointer exception.
For comparing greater and less than, use
if (a != null && b!=null) {
int compareValue = a.compareTo(b);
if (compareValue > 0) {
System.out.println("a is greater than b");
} else if (compareValue < 0) {
System.out.println("b is greater than a");
} else {
System.out.println("a and b are equal");
}
} else {
System.out.println("a or b is null, cannot compare");
}
In my case I had to compare two Integers for equality where both of them could be null. I searched similar topics, but I didn't find anything elegant for this. I came up with simple utility function:
public static boolean integersEqual(Integer i1, Integer i2) {
if (i1 == null && i2 == null) {
return true;
}
if (i1 == null && i2 != null) {
return false;
}
if (i1 != null && i2 == null) {
return false;
}
return i1.intValue() == i2.intValue();
}
// Considering null is less than not-null
public static int integersCompare(Integer i1, Integer i2) {
if (i1 == null && i2 == null) {
return 0;
}
if (i1 == null && i2 != null) {
return -1;
}
return i1.compareTo(i2);
}
Because a comparison method has to be done based on type int (x==y) or class Integer (x.equals(y)) with the right operator:
public class Example {
public static void main(String[] args) {
int[] arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};
for(int j=1; j<arr.length-1; j++)
if((arr[j-1] != arr[j]) && (arr[j] != arr[j+1]))
System.out.println("int>" + arr[j]);
Integer[] I_arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};
for(int j=1; j<I_arr.length-1; j++)
if((!I_arr[j-1].equals(I_arr[j])) && (!I_arr[j].equals(I_arr[j+1])))
System.out.println("Interger>" + I_arr[j]);
}
}
This method compares two Integer's with a null check. See the tests.
public static boolean compare(Integer int1, Integer int2) {
if(int1!=null) {
return int1.equals(int2);
} else {
return int2==null;
}
//inline version:
//return (int1!=null) ? int1.equals(int2) : int2==null;
}
//results:
System.out.println(compare(1,1)); //true
System.out.println(compare(0,1)); //false
System.out.println(compare(1,0)); //false
System.out.println(compare(null,0)); //false
System.out.println(compare(0,null)); //false
System.out.println(compare(null,null)); //true

test if duration is between a range

I have 3 durations
// java.time.Duration
var sec1 = Duration.ofSeconds(1);
var sec2 = Duration.ofSeconds(2);
var min1 = Duration.ofMinutes(5);
and I want to test if sec2 is between sec1 and min1. Something like this
if(sec2.between(sec1, min1))
does not work.
How can I do that?
Update - Solution:
// tests if x is within start (inclusive) and end (inclusive)
boolean isBetween(Duration x, Duration start, Duration end) {
return start.compareTo(x) <= 0 && x.compareTo(end) <= 0;
}
You can do as follows:
if(sec2.compareTo(sec1)>0 && sec2.compareTo(min1)<0)
The description of compareTo method:
public int compareTo(Duration otherDuration) Compares this duration to
the specified Duration.
The comparison is based on the total length of
the durations. It is "consistent with equals", as defined by
Comparable. Parameters: otherDuration - the other duration to compare
to, not null Returns: the comparator value, negative if less,
positive if greater
if (sec1.compareTo(sec2) <= 0 && sec2.compareTo(min1) <= 0)
To know what you're using the https://docs.oracle.com/javase/tutorial/datetime/iso/period.html the Instant is actually what you are comparing but it also is false if it is negative so you still need to make sure the compiler will not throw an error with your return that doesn't use parens.
static boolean isBetween(Duration x, Duration start, Duration end) {
boolean isBetween = false;
if(start.compareTo(x) <= 0 && x.compareTo(end) <= 0) {
isBetween = true;
} else if(start.compareTo(x) > 0 && x.compareTo(end) > 0) {
isBetween = false;
}
return isBetween;
}
The use of Comparator is a best use of the API function to be reusable as again if the function doesn't handle null cases you will get errors. Try to use the type given then check for criteria. If it's a function you are only using for a specific purpose on one duration the different cases like 0, null and out of the range need to be handled.
class DurationComparator implements Comparator<Duration> {
#Override
public int compare(Duration o1, Duration o2) {
int d1 = o1 == null ? 0 : o1.getDuration();
int d2 = o2 == null ? 0 : o2.getDuration();
return d2 - d1;
}
}
This is a better naming for your method still giving you a boolean with the between compare using the Instant. Your solution is only seeing if it not in the range so if you are looking for if it is in between you need to use the compareTo correctly checking both ends of the Duration so this will work.

Java Integer Wrapper behavior [duplicate]

I know that if you compare a boxed primitive Integer with a constant such as:
Integer a = 4;
if (a < 5)
a will automatically be unboxed and the comparison will work.
However, what happens when you are comparing two boxed Integers and want to compare either equality or less than/greater than?
Integer a = 4;
Integer b = 5;
if (a == b)
Will the above code result in checking to see if they are the same object, or will it auto-unbox in that case?
What about:
Integer a = 4;
Integer b = 5;
if (a < b)
?
No, == between Integer, Long etc will check for reference equality - i.e.
Integer x = ...;
Integer y = ...;
System.out.println(x == y);
this will check whether x and y refer to the same object rather than equal objects.
So
Integer x = new Integer(10);
Integer y = new Integer(10);
System.out.println(x == y);
is guaranteed to print false. Interning of "small" autoboxed values can lead to tricky results:
Integer x = 10;
Integer y = 10;
System.out.println(x == y);
This will print true, due to the rules of boxing (JLS section 5.1.7). It's still reference equality being used, but the references genuinely are equal.
If the value p being boxed is an integer literal of type int between
-128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f'
inclusive (§3.10.4), then let a and b be the results of any two boxing
conversions of p. It is always the case that a == b.
Personally I'd use:
if (x.intValue() == y.intValue())
or
if (x.equals(y))
As you say, for any comparison between a wrapper type (Integer, Long etc) and a numeric type (int, long etc) the wrapper type value is unboxed and the test is applied to the primitive values involved.
This occurs as part of binary numeric promotion (JLS section 5.6.2). Look at each individual operator's documentation to see whether it's applied. For example, from the docs for == and != (JLS 15.21.1):
If the operands of an equality
operator are both of numeric type, or
one is of numeric type and the other
is convertible (§5.1.8) to numeric
type, binary numeric promotion is
performed on the operands (§5.6.2).
and for <, <=, > and >= (JLS 15.20.1)
The type of each of the operands of a
numerical comparison operator must be
a type that is convertible (§5.1.8) to
a primitive numeric type, or a
compile-time error occurs. Binary
numeric promotion is performed on the
operands (§5.6.2). If the promoted
type of the operands is int or long,
then signed integer comparison is
performed; if this promoted type is
float or double, then floating-point
comparison is performed.
Note how none of this is considered as part of the situation where neither type is a numeric type.
== will still test object equality. It is easy to be fooled, however:
Integer a = 10;
Integer b = 10;
System.out.println(a == b); //prints true
Integer c = new Integer(10);
Integer d = new Integer(10);
System.out.println(c == d); //prints false
Your examples with inequalities will work since they are not defined on Objects. However, with the == comparison, object equality will still be checked. In this case, when you initialize the objects from a boxed primitive, the same object is used (for both a and b). This is an okay optimization since the primitive box classes are immutable.
Since Java 1.7 you can use Objects.equals:
java.util.Objects.equals(oneInteger, anotherInteger);
Returns true if the arguments are equal to each other and false
otherwise. Consequently, if both arguments are null, true is returned
and if exactly one argument is null, false is returned. Otherwise,
equality is determined by using the equals method of the first
argument.
We should always go for the equals() method for comparison of two integers. It's the recommended practice.
If we compare two integers using == that would work for certain range of integer values (Integer from -128 to 127) due to the JVM's internal optimisation.
Please see examples:
Case 1:
Integer a = 100;
Integer b = 100;
if (a == b) {
System.out.println("a and b are equal");
} else {
System.out.println("a and b are not equal");
}
In above case JVM uses value of a and b from cached pool and return the same object instance(therefore memory address) of integer object and we get both are equal.Its an optimisation JVM does for certain range values.
Case 2: In this case, a and b are not equal because it does not come with the range from -128 to 127.
Integer a = 220;
Integer b = 220;
if (a == b) {
System.out.println("a and b are equal");
} else {
System.out.println("a and b are not equal");
}
Proper way:
Integer a = 200;
Integer b = 200;
System.out.println("a == b? " + a.equals(b)); // true
tl;dr my opinion is to use a unary + to trigger the unboxing on one of the operands when checking for value equality, and simply use the maths operators otherwise. Rationale follows:
It has been mentioned already that == comparison for Integer is identity comparison, which is usually not what a programmer want, and that the aim is to do value comparison; still, I've done a little science about how to do that comparison most efficiently, both in term of code compactness, correctness and speed.
I used the usual bunch of methods:
public boolean method1() {
Integer i1 = 7, i2 = 5;
return i1.equals( i2 );
}
public boolean method2() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2.intValue();
}
public boolean method3() {
Integer i1 = 7, i2 = 5;
return i1.intValue() == i2;
}
public boolean method4() {
Integer i1 = 7, i2 = 5;
return i1 == +i2;
}
public boolean method5() { // obviously not what we want..
Integer i1 = 7, i2 = 5;
return i1 == i2;
}
and got this code after compilation and decompilation:
public boolean method1() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
return var1.equals( var2 );
}
public boolean method2() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method3() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method4() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2.intValue() == var1.intValue() ) {
return true;
} else {
return false;
}
}
public boolean method5() {
Integer var1 = Integer.valueOf( 7 );
Integer var2 = Integer.valueOf( 5 );
if ( var2 == var1 ) {
return true;
} else {
return false;
}
}
As you can easily see, method 1 calls Integer.equals() (obviously), methods 2-4 result in exactly the same code, unwrapping the values by means of .intValue() and then comparing them directly, and method 5 just triggers an identity comparison, being the incorrect way to compare values.
Since (as already mentioned by e.g. JS) equals() incurs an overhead (it has to do instanceof and an unchecked cast), methods 2-4 will work with exactly the same speed, noticingly better than method 1 when used in tight loops, since HotSpot is not likely to optimize out the casts & instanceof.
It's quite similar with other comparison operators (e.g. </>) - they will trigger unboxing, while using compareTo() won't - but this time, the operation is highly optimizable by HS since intValue() is just a getter method (prime candidate to being optimized out).
In my opinion, the seldom used version 4 is the most concise way - every seasoned C/Java developer knows that unary plus is in most cases equal to cast to int/.intValue() - while it may be a little WTF moment for some (mostly those who didn't use unary plus in their lifetime), it arguably shows the intent most clearly and most tersely - it shows that we want an int value of one of the operands, forcing the other value to unbox as well. It is also unarguably most similar to the regular i1 == i2 comparison used for primitive int values.
My vote goes for i1 == +i2 & i1 > i2 style for Integer objects, both for performance & consistency reasons. It also makes the code portable to primitives without changing anything other than the type declaration. Using named methods seems like introducing semantic noise to me, similar to the much-criticized bigInt.add(10).multiply(-3) style.
== checks for reference equality, however when writing code like:
Integer a = 1;
Integer b = 1;
Java is smart enough to reuse the same immutable for a and b, so this is true: a == b. Curious, I wrote a small example to show where java stops optimizing in this way:
public class BoxingLol {
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
Integer a = i;
Integer b = i;
if (a != b) {
System.out.println("Done: " + i);
System.exit(0);
}
}
System.out.println("Done, all values equal");
}
}
When I compile and run this (on my machine), I get:
Done: 128
Calling
if (a == b)
Will work most of the time, but it's not guaranteed to always work, so do not use it.
The most proper way to compare two Integer classes for equality, assuming they are named 'a' and 'b' is to call:
if(a != null && a.equals(b)) {
System.out.println("They are equal");
}
You can also use this way which is slightly faster.
if(a != null && b != null && (a.intValue() == b.intValue())) {
System.out.println("They are equal");
}
On my machine 99 billion operations took 47 seconds using the first method, and 46 seconds using the second method. You would need to be comparing billions of values to see any difference.
Note that 'a' may be null since it's an Object. Comparing in this way will not cause a null pointer exception.
For comparing greater and less than, use
if (a != null && b!=null) {
int compareValue = a.compareTo(b);
if (compareValue > 0) {
System.out.println("a is greater than b");
} else if (compareValue < 0) {
System.out.println("b is greater than a");
} else {
System.out.println("a and b are equal");
}
} else {
System.out.println("a or b is null, cannot compare");
}
In my case I had to compare two Integers for equality where both of them could be null. I searched similar topics, but I didn't find anything elegant for this. I came up with simple utility function:
public static boolean integersEqual(Integer i1, Integer i2) {
if (i1 == null && i2 == null) {
return true;
}
if (i1 == null && i2 != null) {
return false;
}
if (i1 != null && i2 == null) {
return false;
}
return i1.intValue() == i2.intValue();
}
// Considering null is less than not-null
public static int integersCompare(Integer i1, Integer i2) {
if (i1 == null && i2 == null) {
return 0;
}
if (i1 == null && i2 != null) {
return -1;
}
return i1.compareTo(i2);
}
Because a comparison method has to be done based on type int (x==y) or class Integer (x.equals(y)) with the right operator:
public class Example {
public static void main(String[] args) {
int[] arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};
for(int j=1; j<arr.length-1; j++)
if((arr[j-1] != arr[j]) && (arr[j] != arr[j+1]))
System.out.println("int>" + arr[j]);
Integer[] I_arr = {-32735, -32735, -32700, -32645, -32645, -32560, -32560};
for(int j=1; j<I_arr.length-1; j++)
if((!I_arr[j-1].equals(I_arr[j])) && (!I_arr[j].equals(I_arr[j+1])))
System.out.println("Interger>" + I_arr[j]);
}
}
This method compares two Integer's with a null check. See the tests.
public static boolean compare(Integer int1, Integer int2) {
if(int1!=null) {
return int1.equals(int2);
} else {
return int2==null;
}
//inline version:
//return (int1!=null) ? int1.equals(int2) : int2==null;
}
//results:
System.out.println(compare(1,1)); //true
System.out.println(compare(0,1)); //false
System.out.println(compare(1,0)); //false
System.out.println(compare(null,0)); //false
System.out.println(compare(0,null)); //false
System.out.println(compare(null,null)); //true

One liner to check two decimal strings differ only by 1 ulp

I have two decimal numbers in String form that are rounded slightly differently. I want a function that would treat them as "equal" if they only differ by 1 ulp (i.e. only the last digit differs by 1).
Currently the most readable form I can come up with is like:
private static boolean diffByUlp(String oldVal, String newVal) {
BigDecimal nb = new BigDecimal(newVal);
return nb.subtract(new BigDecimal(oldVal)).abs().equals(nb.ulp());
}
However, I'd really like a way to do this in one expression (so it fits in an if statement) and avoid using the expensive BigDecimals.
(BTW: they differ by more than 1 double (binary) ulp.)
Any suggestions?
I assume you are looking for a performance effective solution since you've already mentioned that using BigDecimal is too expensive in your case. Although giving advice on performance without knowing the whole context is quite tricky. You may consider a solution based on comparing characters from both decimal numbers stored as a String. It may give you a quick boost if numbers you compare are usually different starting from very first digits (e.g. comparing 120.0001 with 512.0 can be easily tracked just by comparing first character in both strings). But if for most cases your numbers are pretty close then you might stick to BigDecimal - it's all about measuring the performance with real data.
Below you can find an exemplary solution based on comparing characters from strings. It handles a case where two decimal numbers uses different precision. Also when comparing "1.00" with "1.00001" the first number is "treated" as "1.00000". You can use this class as a utility class that provides you a single static method that you can use in any if statement.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
final class StringDecimal {
private static final Map<Integer, Integer> charToInt = new ConcurrentHashMap<>();
static {
charToInt.put(48, 0);
charToInt.put(49, 1);
charToInt.put(50, 2);
charToInt.put(51, 3);
charToInt.put(52, 4);
charToInt.put(53, 5);
charToInt.put(54, 6);
charToInt.put(55, 7);
charToInt.put(56, 8);
charToInt.put(57, 9);
}
private static boolean areEqual(String num1, String num2) {
int size = Math.min(num1.length(), num2.length()) - 1;
// 1. Compare first n-1 characters where n is max common length for both strings
for (int i = 0; i < size; i++) {
if (num1.charAt(i) != num2.charAt(i)) {
return false;
}
}
int lastDigitDiff = Math.max(num1.charAt(size), num2.charAt(size)) - Math.min(num1.charAt(size), num2.charAt(size));
// 2. Check last common digit
if (lastDigitDiff > 1) {
return false;
}
// 3. If both decimal numbers have same size, they are equal at this moment
if (num1.length() == num2.length()) {
return true;
}
if (num1.length() > num2.length()) {
return testRemainingDigits(num1, size);
}
return testRemainingDigits(num2, size);
}
private static boolean testRemainingDigits(String num, int size) {
int lastDigitsSum = 0;
int lastDigit = charToInt.getOrDefault((int) num.charAt(num.length() - 1), 0);
// 1. Check if last digit is equal to 1
if (lastDigit > 1) {
return false;
}
// 2. Sum all remaining digits from longer string and accept sum == 1
for (int i = num.length() - 1; i > size; i--) {
lastDigitsSum += charToInt.getOrDefault((int) num.charAt(i), 0);
}
return lastDigit == 0 && lastDigitsSum == 0 ||
lastDigit == 1 && lastDigitsSum == 1;
}
public static void main(String[] args) {
List<List<Object>> numbers = Arrays.asList(
Arrays.asList("1.00", "1.000000", true),
Arrays.asList("120.0", "121.0", false),
Arrays.asList("120.0", "120.1", true),
Arrays.asList("1024.00001", "1024.00000", true),
Arrays.asList("1024.00002", "1024.00000", false),
Arrays.asList("1024.00001", "1024.0000", true),
Arrays.asList("1024.00001", "1024", true),
Arrays.asList("1024.00010", "1024", false),
Arrays.asList("1024.00002", "1024", false),
Arrays.asList("1024.00001", "1025.00001", false)
);
for (List<Object> data : numbers) {
String num1 = (String) data.get(0);
String num2 = (String) data.get(1);
boolean expected = (boolean) data.get(2);
boolean result = areEqual(num1, num2);
String status = expected == result ? "OK" : "FAILED";
System.out.println("["+status+"] " + num1 + " == " + num2 + " ? " + result);
}
}
}
It's very imperative, but it's still quite easy to understand what happens under the hood. Complexity of this algorithm is O(n).
Running this exemplary program produces following output:
[OK] 1.00 == 1.000000 ? true
[OK] 120.0 == 121.0 ? false
[OK] 120.0 == 120.1 ? true
[OK] 1024.00001 == 1024.00000 ? true
[OK] 1024.00002 == 1024.00000 ? false
[OK] 1024.00001 == 1024.0000 ? true
[OK] 1024.00001 == 1024 ? true
[OK] 1024.00010 == 1024 ? false
[OK] 1024.00002 == 1024 ? false
[OK] 1024.00001 == 1025.00001 ? false
I hope it will help you coming up with the best solution to your problem.
You have high expectations in a very "floating" area.
Still one, not so serious, answer:
static boolean probablySame(String x, String y) {
return Math.abs(x.hashCode() - y.hashCode()) <= 1;
}
So you want to compactly check if two decimal values only differ by at most 1. For example 3.2 and 2.4 (difference is 0.8).
First you should note that the only purpose of BigDecimal is to provide infinite space and precision in contrast to the limited datatype double (same holds for BigInteger and int). However you only use it to parse a decimal value from a String. Using that class only for that purpose is quite a big overhead, as you already mentioned. Parsing values can also be done with the Double#parseDouble method (documentation), it returns a compact small double value.
All in all your code could look like this:
private static boolean differAtMostByOne(final String oldVal, final String newVal) {
final double oldValAsDouble = Double.parseDouble(oldVal);
final double newValAsDouble = Double.parseDouble(newVal),
final double difference = Math.abs(oldValAsDouble - newValAsDouble);
final double compareTo = 1.0;
final double precision = 0.000001;
final boolean differByAtMostOne = difference <= compareTo + precision;
return differByAtMostOne;
}
Or the same compact:
private static boolean differAtMostByOne(final String oldVal, final String newVal) {
return Math.abs(Double.parseDouble(oldVal) - Double.parseDouble(newVal)) < 1.000001;
}
Note that a direct comparison with the value 1.0 should be avoided when comparing with decimal values. Instead you should allow a small region around the value to account for precision loss.
Else it could be that you input values whose difference is exactly 1 but the computer may represent it by a value like 1.000000000000000001 and the program should also accept it thus the precision region.
Assuming you need this only for Strings with the same lenght. Following might be a possible solution.
check that the strings are equal, except the last digit
check that the last digit is not more of then by one
The snippet should only demonstrate the principal. Further optimization possible.
static boolean diffByUlp(String s1, String s2) {
for (int i = 0; i < s1.length() - 1; i++) {
if (s1.charAt(i) != s2.charAt(i)) {
return false;
}
}
char c1 = s1.charAt(s1.length() - 1);
char c2 = s2.charAt(s2.length() - 1);
if (c1 >= c2) {
return c1-c2 <= 1;
}
return c2-c1 <= 1;
}

How to test if a double is an integer

Is it possible to do this?
double variable;
variable = 5;
/* the below should return true, since 5 is an int.
if variable were to equal 5.7, then it would return false. */
if(variable == int) {
//do stuff
}
I know the code probably doesn't go anything like that, but how does it go?
Or you could use the modulo operator:
(d % 1) == 0
if ((variable == Math.floor(variable)) && !Double.isInfinite(variable)) {
// integer type
}
This checks if the rounded-down value of the double is the same as the double.
Your variable could have an int or double value and Math.floor(variable) always has an int value, so if your variable is equal to Math.floor(variable) then it must have an int value.
This also doesn't work if the value of the variable is infinite or negative infinite hence adding 'as long as the variable isn't inifinite' to the condition.
Guava: DoubleMath.isMathematicalInteger. (Disclosure: I wrote it.) Or, if you aren't already importing Guava, x == Math.rint(x) is the fastest way to do it; rint is measurably faster than floor or ceil.
public static boolean isInt(double d)
{
return d == (int) d;
}
Try this way,
public static boolean isInteger(double number){
return Math.ceil(number) == Math.floor(number);
}
for example:
Math.ceil(12.9) = 13; Math.floor(12.9) = 12;
hence 12.9 is not integer, nevertheless
Math.ceil(12.0) = 12; Math.floor(12.0) =12;
hence 12.0 is integer
Here is a good solution:
if (variable == (int)variable) {
//logic
}
Consider:
Double.isFinite (value) && Double.compare (value, StrictMath.rint (value)) == 0
This sticks to core Java and avoids an equality comparison between floating point values (==) which is consdered bad. The isFinite() is necessary as rint() will pass-through infinity values.
Here's a version for Integer and Double:
private static boolean isInteger(Double variable) {
if ( variable.equals(Math.floor(variable)) &&
!Double.isInfinite(variable) &&
!Double.isNaN(variable) &&
variable <= Integer.MAX_VALUE &&
variable >= Integer.MIN_VALUE) {
return true;
} else {
return false;
}
}
To convert Double to Integer:
Integer intVariable = variable.intValue();
Similar to SkonJeet's answer above, but the performance is better (at least in java):
Double zero = 0d;
zero.longValue() == zero.doubleValue()
My simple solution:
private boolean checkIfInt(double value){
return value - Math.floor(value) == 0;
}
public static boolean isInteger(double d) {
// Note that Double.NaN is not equal to anything, even itself.
return (d == Math.floor(d)) && !Double.isInfinite(d);
}
A simple way for doing this could be
double d = 7.88; //sample example
int x=floor(d); //floor of number
int y=ceil(d); //ceil of number
if(x==y) //both floor and ceil will be same for integer number
cout<<"integer number";
else
cout<<"double number";
My solution would be
double variable=the number;
if(variable-(int)variable=0.0){
// do stuff
}
you could try in this way: get the integer value of the double, subtract this from the original double value, define a rounding range and tests if the absolute number of the new double value(without the integer part) is larger or smaller than your defined range. if it is smaller you can intend it it is an integer value. Example:
public final double testRange = 0.2;
public static boolean doubleIsInteger(double d){
int i = (int)d;
double abs = Math.abs(d-i);
return abs <= testRange;
}
If you assign to d the value 33.15 the method return true. To have better results you can assign lower values to testRange (as 0.0002) at your discretion.
Personally, I prefer the simple modulo operation solution in the accepted answer.
Unfortunately, SonarQube doesn't like equality tests with floating points without setting a round precision. So we have tried to find a more compliant solution. Here it is:
if (new BigDecimal(decimalValue).remainder(new BigDecimal(1)).equals(BigDecimal.ZERO)) {
// no decimal places
} else {
// decimal places
}
Remainder(BigDecimal) returns a BigDecimal whose value is (this % divisor). If this one's equal to zero, we know there is no floating point.
Because of % operator cannot apply to BigDecimal and int (i.e. 1) directly, so I am using the following snippet to check if the BigDecimal is an integer:
value.stripTrailingZeros().scale() <= 0
Similar (and probably inferior) to Eric Tan's answer (which checks scale):
double d = 4096.00000;
BigDecimal bd = BigDecimal.valueOf(d);
String s = bd.stripTrailingZeros().toPlainString();
boolean isInteger = s.indexOf(".")==-1;
Here's a solution:
float var = Your_Value;
if ((var - Math.floor(var)) == 0.0f)
{
// var is an integer, so do stuff
}

Categories

Resources