verifying value equals exactly 0.00 - java

I'm looking to calculate if a value of a variable in java is equal to 0.00 which is currently defined as a big decimal .
I have tried a variety of ways to do this including:
tempListPrice.getAmount() == 0.00;
tempListPrice.getAmount().equals(0.00);
public static final zeroed = 0.00
tempListPrice.getAmount().equals(zeroed);
Keep in mind, I've done quite a bit of googling to try to find an easy way to compare this. How do I compare the value of tempListPrice to see if it equals 0.00 , which is defined earlier as a big decimal datatype.
How do I do this? (Sorry Im quite new to Java).
Thanks

Okay, upon further research you will want equals or compareTo. You probably want
tempListPrice.getAmount().compareTo(BigDecimal.ZERO);
or
tempListPrice.getAmount().equals(BigDecimal.ZERO);
But honestly need to decide which better fits the semantics of your program. Keep in mind that the reason this is tricky is because floats don't really have a notion of exactly equals, they're intrinsically fuzzy, approximate entities. You will need to carefully review your code to make sure this is valid for your circumstances.
Anyway, the following points from the Javadoc should be enough for you to decide:
(equals) Compares this BigDecimal with the specified Object for equality. Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method).
cf.
(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) 0), where is one of the six comparison operators.

BigDecimal val = new BigDecimal("0.00");
BigDecimal test = new BigDecimal("0.00");
boolean isEqual = val.equals(test);
System.out.println("val " + val.toString() + " test " + test + " comp = " + isEqual);
outputs
val 0.00 test 0.00 comp = true
BigDecimal val = new BigDecimal("0.000");
BigDecimal test = new BigDecimal("0.00");
boolean isEqual = val.equals(test);
System.out.println("val " + val.toString() + " test " + test + " comp = " + isEqual);
outputs
val 0.000 test 0.00 comp = false

As the prior answers have noted, you need to be sure that the methods described meet your requirements. If, as the variable name implies, you are comparing currency amounts to zero, an alternative might be to store the amount as two int variables, as follows (assumes dollars but could be any other currency):
public boolean isZero (int dollars, int cents) {
return (dollars == 0 && cents == 0);
}
In short, is a BigDecimal variable necessary for your purposes?

Related

Can you replicate the Floor function found in Excel in Java?

I have searched the internet but have not found any solutions for my question.
I would like to be able to use the same/replicate the type of FLOOR function found in Excel in Java. In particular I would like to be able to provide a value (double or preferably BigDecimal) and round down to the nearest multiple of a significance I provide.
Examples 1:
Value = 24,519.30235
Significance = 0.01
Returned Value = 24,519.30
Example 2:
Value = 76.81485697
Significance = 1
Returned Value = 76
Example 3:
Value = 12,457,854
Significance = 100
Returned Value = 12,457,800
I am pretty new to java and was wondering if someone knew if an API already includes the function or if they would be kind enough to give me a solution to the above. I am aware of BigDecimal but I might have missed the correct function.
Many thanks
Yes you can.
Lets say given numbers are
76.21445
and
0.01
what you can do is multiply 76.21445 by 100 (or divide per 0.01)
round the result to nearest or lower integer (depending which one you want)
and than multiply it by the number again.
Note that it may not exactly print what you want if you will not go for the numbers with decimal precision. (The problem of numbers which in the binary format are not finite in extansion). Also in Math you have the round function taking doing pretty much what you want.
http://docs.oracle.com/javase/7/docs/api/java/lang/Math.html you use it like this
round(200.3456, 2);
one Example Code could be
public static void main(String[] args) {
BigDecimal value = new BigDecimal("2.0");
BigDecimal significance = new BigDecimal("0.5");
for (int i = 1; i <= 10; i++) {
System.out.println(value + " --> " + floor(value, significance));
value = value.add(new BigDecimal("0.1"));
}
}
private static double floor(BigDecimal value, BigDecimal significance) {
double result = 0;
if (value != null) {
result = value.divide(significance).doubleValue();
result = Math.floor(result) * significance.doubleValue();
}
return result;
}
To round a BigDecimal, you can use setScale(). In your case, you want RoundingMode.FLOOR.
Now you need to determine the number of digits from the "significance". Use Math.log10(significance) for that. You'll probably have to round the result up.
If the result is negative, then you have a significance < 1. In this case, use setScale(-result, RoundingMode.FLOOR) to round to N digits.
If it's > 1, then use this code:
value
.divide(significance)
.setScale(0, RoundingMode.FLOOR)
.multiply(significance);
i.e. 1024 and 100 gives 10.24 -> 10 -> 1000.

Why is BigDecimal natural ordering inconsistent with equals?

From the Javadoc for BigDecimal:
Note: care should be exercised if BigDecimal objects are used as keys in a SortedMap or elements in a SortedSet since BigDecimal's natural ordering is inconsistent with equals.
For example, if you create a HashSet and add new BigDecimal("1.0") and new BigDecimal("1.00") to it, the set will contain two elements (because the values have different scales, so are non-equal according to equals and hashCode), but if you do the same thing with a TreeSet, the set will contain only one element, because the values compare as equal when you use compareTo.
Is there any specific reason behind this inconsistency?
From the OpenJDK implementation of BigDecimal:
/**
* Compares this {#code BigDecimal} with the specified
* {#code Object} for equality. Unlike {#link
* #compareTo(BigDecimal) compareTo}, this method considers two
* {#code BigDecimal} objects equal only if they are equal in
* value and scale (thus 2.0 is not equal to 2.00 when compared by
* this method).
*
* #param x {#code Object} to which this {#code BigDecimal} is
* to be compared.
* #return {#code true} if and only if the specified {#code Object} is a
* {#code BigDecimal} whose value and scale are equal to this
* {#code BigDecimal}'s.
* #see #compareTo(java.math.BigDecimal)
* #see #hashCode
*/
#Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflate().equals(xDec.inflate());
}
More from the implementation:
* <p>Since the same numerical value can have different
* representations (with different scales), the rules of arithmetic
* and rounding must specify both the numerical result and the scale
* used in the result's representation.
Which is why the implementation of equals takes scale into consideration. The constructor that takes a string as a parameter is implemented like this:
public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length());
}
where the third parameter will be used for the scale (in another constructor) which is why the strings 1.0 and 1.00 will create different BigDecimals (with different scales).
From Effective Java By Joshua Bloch:
The final paragraph of the compareTo contract, which is a strong
suggestion rather than a true provision, simply states that the
equality test imposed by the compareTo method should generally return
the same results as the equals method. If this provision is obeyed,
the ordering imposed by the compareTo method is said to be consistent
with equals. If it’s violated, the ordering is said to be inconsistent
with equals. A class whose compareTo method imposes an order that is
inconsistent with equals will still work, but sorted collections
containing elements of the class may not obey the general contract of
the appropriate collection interfaces (Collection, Set, or Map). This
is because the general contracts for these interfaces are defined in
terms of the equals method, but sorted collections use the equality
test imposed by compareTo in place of equals. It is not a catastrophe
if this happens, but it’s something to be aware of.
The behaviour seems reasonable in the context of arithmetic precision where trailing zeros are significant figures and 1.0 does not carry the same meaning as 1.00. Making them unequal seems to be a reasonable choice.
However from a comparison perspective neither of the two is greater or less than the other and the Comparable interface requires a total order (i.e. each BigDecimal must be comparable with any other BigDecimal). The only reasonable option here was to define a total order such that the compareTo method would consider the two numbers equal.
Note that inconsistency between equal and compareTo is not a problem as long as it's documented. It is even sometimes exactly what one needs.
BigDecimal works by having two numbers, an integer and a scale. The integer is the "number" and the scale is the number of digits to the right of the decimal place. Basically a base 10 floating point number.
When you say "1.0" and "1.00" these are technically different values in BigDecimal notation:
1.0
integer: 10
scale: 1
precision: 2
= 10 x 10 ^ -1
1.00
integer: 100
scale: 2
precision: 3
= 100 x 10 ^ -2
In scientific notation you wouldn't do either of those, it should be 1 x 10 ^ 0 or just 1, but BigDecimal allows it.
In compareTo the scale is ignored and they are evaluated as ordinary numbers, 1 == 1. In equals the integer and scale values are compared, 10 != 100 and 1 != 2. The BigDecimal equals method ignores the object == this check I assume because the intention is that each BigDecimal is treated as a type of number, not like an object.
I would liken it to this:
// same number, different types
float floatOne = 1.0f;
double doubleOne = 1.0;
// true: 1 == 1
System.out.println( (double)floatOne == doubleOne );
// also compare a float to a double
Float boxFloat = floatOne;
Double boxDouble = doubleOne;
// false: one is 32-bit and the other is 64-bit
System.out.println( boxInt.equals(boxDouble) );
// BigDecimal should behave essentially the same way
BigDecimal bdOne1 = new BigDecimal("1.0");
BigDecimal bdOne2 = new BigDecimal("1.00");
// true: 1 == 1
System.out.println( bdOne1.compareTo(bdOne2) );
// false: 10 != 100 and 1 != 2 ensuring 2 digits != 3 digits
System.out.println( bdOne1.equals(bdOne2) );
Because BigDecimal allows for a specific "precision", comparing both the integer and the scale is more or less the same as comparing both the number and the precision.
Although there is a semi-caveat to that when talking about BigDecimal's precision() method which always returns 1 if the BigDecimal is 0. In this case compareTo && precision evaluates true and equals evaluates false. But 0 * 10 ^ -1 should not equal 0 * 10 ^ -2 because the former is a 2 digit number 0.0 and the latter is a 3 digit number 0.00. The equals method is comparing both the value and the number of digits.
I suppose it is weird that BigDecimal allows trailing zeroes but this is basically necessary. Doing a mathematical operation like "1.1" + "1.01" requires a conversion but "1.10" + "1.01" doesn't.
So compareTo compares BigDecimals as numbers and equals compares BigDecimals as BigDecimals.
If the comparison is unwanted, use a List or array where this doesn't matter. HashSet and TreeSet are of course designed specifically for holding unique elements.
The answer is pretty short. equals() method compares objects while compareTo() compares values. In case of BigDecimal different objects can represent same value. Thats why equals() might return false, while compareTo() returns 0.
equal objects => equal values
equal values =/> equal objects
Object is just a computer representation of a some real world value. For example same picture might be represented in a GIF and JPEG formats. Thats very like BigDecimal, where same value might have distinct representations.

Overriding hashCode() in Java

I created a class "Book":
public class Book {
public static int idCount = 1;
private int id;
private String title;
private String author;
private String publisher;
private int yearOfPublication;
private int numOfPages;
private Cover cover;
...
}
And then i need to override the hashCode() and equals() methods.
#Override
public int hashCode() {
int result = id; // !!!
result = 31 * result + (title != null ? title.hashCode() : 0);
result = 31 * result + (author != null ? author.hashCode() : 0);
result = 31 * result + (publisher != null ? publisher.hashCode() : 0);
result = 31 * result + yearOfPublication;
result = 31 * result + numOfPages;
result = 31 * result + (cover != null ? cover.hashCode() : 0);
return result;
}
It's no problem with equals(). I just wondering about one thing in hashCode() method.
Note: IntelliJ IDEA generated that hashCode() method.
So, is it OK to set the result variable to id, or should i use some prime number?
What is the better choice here?
Thanks!
Note that only the initial value of the result is set to id, not the final one. The final value is calculated by combining that initial value with hash codes of other parts of the object, multiplied by a power of a small prime number (i.e. 31). Using id rather than an arbitrary prime is definitely right in this context.
In general, there is no advantage to hash code being prime (it's the number of hash buckets that needs to be prime). Using an int as its own hash code (in your case, that's id and numOfPages) is a valid approach.
It helps to know what the hashCode is used for. It's supposed to help you map a theoretically infinite set of objects to fitting in a small number of "bins", with each bin having a number, and each object saying which bin it wants to go in based on its hashCode. The question is not whether it's okay to do one thing or another, but whether what you want to do matches what the hashCode function is for.
As per http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode(), it's not about the number you return, it's about how it behaves for different objects of the same class.
If the object doesn't change, the hashCode must be the same value every time you call the hashCode() function.
Two objects that are equal according to .equals, must have the same hashCode.
Two objects that are not equal may have the same hashCode. (if this wasn't the case, there would be no point in using the hashCode at all, because every object already has a unique object pointer)
If you're reimplementing the hashCode function, the most important thing is to either rely on a tool to generate it for you, or to use code you understand that obeys those rules. The basic Java hashCode function uses an incredibly well-researched, seemingly simple bit of code for String hashing, so the code you see is based on turning everything into Strings and falling back to that.
If you don't know why that works, don't touch it. Just rely on it working and move on. That 31 is ridiculously important and ensures an even hashing distribution. See Why does Java's hashCode() in String use 31 as a multiplier? for the why on that one.
However, this might also be way more than you need. You could use id, but then you're basically negating the reason to use a hashCode (because now every object will want to be in a bin on its own, turning any hashed collection into a flat array. Kind of silly).
If you know the distribution of your id values, there are far easier hashCodes to come up with. Say you know they are always between 0 and Interger.MAX_VALUE, and you know there are never any gaps between ids, you could simply generate a hashCode like
final int modulus = Intereger.MAX_VALUE / 255;
int hashCode() {
return this.id % modulus;
}
now, you have a hashCode optimised for 255 bins, fulfilling the necessary requirements for an acceptable hashCode function.
Note : In my answer I am assuming that you know how hash code is meant to be used. The following just talks about any potential optimization using a non-zero constant for the initial value of result may produce.
If id is rarely 0 then it's fine to use it. However, if it's 0 frequently you should use some constant instead (just using 1 should be fine). The reason you want for it to be non-zero is so that the 31 * result part always adds some value to the hash. That way say if object A has all fields null or 0 except for yearOfPublication = 1 and object B has all fields null or 0 except for numOfPages = 1 the hash codes will be:
A.hashCode() => initialValue * 31 ^ 4 + 1
B.hashCode() => initialValue * 31 ^ 5 + 1
As you can see if initialValue is 0 then both hash codes are the same, however if it's not 0 then they will be different. It is preferable for them to be different so as to reduce collisions in data structures that use the hash code like HashMap.
That said, in your example of the Book class it is likely that id will never be 0. In fact, if id uniquely identifies the Book then you can have the hashCode() method just return the id.

Hashcode generated by Eclipse

In SO I have read several answers related to the implementation of hashcode and the suggestion to use the XOR operator. (E.g. Why are XOR often used in java hashCode() but another bitwise operators are used rarely?).
When I use Eclipse to generate the hashcode function where field is an object and timestamp a long, the output is:
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ field == null) ? 0 : field.hashCode());
return result;
}
Is there any reason by not using the XOR operator like below?
result = prime * result + (int) (timestamp ^ (timestamp >>> 32));
Eclipse takes the safe way out. Although the calculation method that uses a prime, a multiplication, and an addition is slower than a single XOR, it gives you an overall better hash code in situations when you have multiple fields.
Consider a simple example - a class with two Strings, a and b. You can use
a.hashCode() ^ b.hashCode()
or
a.hashCode() * 31 + b.hashCode()
Now consider two objects:
a = "ABC"; b = "XYZ"
and
a = "XYZ"; b = "ABC"
The first method will produce identical hash codes for them, because XOR is symmetric; the second method will produce different hash codes, which is good, because the objects are not equal. In general, you want non-equal objects to have different hash codes as often as possible, to improve performance of hash-based containers of these objects. The 31*a+b method achieves this goal better than XOR.
Note that when you are dealing with portions of the same object, as in
timestamp ^ (timestamp >>> 32)
the above argument is much weaker: encountering two timestamps such that the only difference between them is that their upper and lower parts are swapped is harder to imagine than two objects with swapped a and b field values.

Floating Point Numbers

This seems like a real simple question but I just to want clear my doubt. I am looking at code which some other developer wrote. There are some calculations involving floating-point numbers.
Example: Float fNotAvlbl = new Float(-99); Why is he creating a new object? What would happen if we do Float fNotAvlbl = -99;(-99 is used as flag here to indicate Not Applicable) Later down the code, we define:
fltValue1 = 0.00f;
fltValue2 = 0.00f;
and populate these two values with a method call which returns float. After that we again convert these two values into Float Objects with:
fltVal1 = new Float(fltValue1);
fltVal2 = new Float(fltValue2);
and than do a comparison if(fltVal1.compareTo(fNotAvailable) == 0) do something.
Is it all because compareTo expects Wrapper Class Objects?
I apologize if this is a real basic question.
Writing Float fNotAvlbl = -99; relies on autoboxing, which has only been added in Java 5, so older code could not use it.
Using -99 as a Float value to mean "Not Applicable" is really, really bad. Either use null or Float.Nan
fltVal1.compareTo(fNotAvailable) == 0 means exactly the same as fltValue1==fltValue2
Comparing float values for strict equality should not be done because it will often fail to work as expected. Read The Float-Point Guide to understand why.
You don't need the wrappers at all
Even if you needed them, using the constructor is not preferred - use Float.valueOf(..) instead.
On the subject of what compareTo() does compared with ==
float a = Float.NaN;
float b = Float.NaN;
System.out.println(a + " == " + b + " is " + (a == b));
System.out.println(a + ".compareTo(" + b + ") is " + ((Float) a).compareTo(b));
float c = -0.0f;
float d = 0.0f;
System.out.println(c + " == " + d + " is " + (c == d));
System.out.println(c + ".compareTo(" + d + ") is " + ((Float) c).compareTo(d));
prints
NaN == NaN is false
NaN.compareTo(NaN) is 0
-0.0 == 0.0 is true
-0.0.compareTo(0.0) is -1
compareTo compares the binary representation (after normalising all NaN values to be the same) As the binary representation for -0.0f and 0.0f are different compareTo does not return 0. There is no special handling in the code other that to use floatToIntBits() and compare that instea dof using ==
The comparison may be using the Float object rather than the built-in float type because of the inherent issues with floating point comparison. Because of the way that floating point numbers are stored on a computer system occasionally the equality comparison between two floating point numbers throws up false negatives. The compareTo from Float may take this into account. The original author possibly at least thought it did.
You can also write your own floating point comparison algorithm that checks for a difference within a reasonable standard deviation for your system. You can also use the method used by equals in Float, which looks at the integer value of the floating point bits for each number.
Note that using Float in and of itself doesn't fix this problem, as the problem is a round-off error in storage.

Categories