I have following two BigDecimal objects.
BigDecimal one = new BigDecimal(3.0);
BigDecimal two = new BigDecimal(3.00);
System.out.println(one.scale());//0
System.out.println(two.scale());//0
System.out.println(one.equals(two));//true
I've read JavaDocs, but anywhere can't understand what is difference between equals and compareTo method. JavaDoc says that these objects isn't equal by equals method and result must be false, but result is true. I'm confused.
You need to use the String constructor to get the correct scales, because the BigDecimal(double) will get the small scale possible
translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.
More precision about the documentations :
BigDecimal.equals(Object)
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).
BigDecimal.compareTo(BigDecimal)
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.
You will find that the equals use the scale for the comparison, giving some "strange" result.
BigDecimal bd1 = new BigDecimal("2"); //scale 0
BigDecimal bd2 = new BigDecimal("2.00"); //scale 2
bd1.equals(bd2); //false
bd1.compareTo(bd2); //0 => which means equivalent
It's better to use compareTo for BigDecimal. This method will return a number greater than zero if a > b, 0 if a == b, and less than zero if a < b
Change new BigDecimal(3.0); to new BigDecimal("3.0"); and you will see the difference.
You used the constructor new BigDecimal(double val) with a double-literal which value is just 3 it doesn't matter if you write 3.0 or 3.0000.
Also be careful with this constructor since it represents the exact decimal representation of the double's binary floating-point value, therefor new BigDecimal(0.1) creates a BigDecimal with the value 0.1000000000000000055511151231257827021181583404541015625 (See JavaDoc)
Better (always) use the constructor new BigDecimal(String val).
Related
I researched this a lot and I know something about precision errors in the doubles; however I couldnt find the answer. My question is: is it always safe to compare double constants? What do I mean by that is, just reading the double from a string or creating in the source code. No operation (adding, subtracting etc.) will be done on them. If I create a variable like
double c = 3.0.
Will the following equation will always be true? c==3.0000.
For example is there any possibility to see wrong evaluation of an equation like this 1.23456789 < 1.23456788?
It's always safe; with one caveat.
Here's an example:
1.232342134214321412421 == 1.232342134214321412422
That is true; all double constants are silently rounded to the nearest representable double, and for both of these numbers, it is the same double.
Thus, given 2 actual mathematical numbers A and B where A < B, then if you turn those numbers into double literals and run these 3 expressions on it, you get the following scenarios:
If A and B are rounded to different doubles, you get guarantees:
A < B will be true
A == B will be false
A > B will be false
If A and B are really close to each other, they may round to the same double, and you get:
A < B will be false
A == B will be true
A > B will be false
In other words, 'less than' and 'greater than' can be bent into being equal, but a lesser number will never be erroneously treated as larger.
For example is there any possibility to see wrong evaluation of an equation like this 1.23456789 < 1.23456788?
Yes, that is possible, because you can write floating-point literals with arbitrary numbers of digits, and these will be approximated to the nearest value that fits in a double when they are interpreted by the compiler.
For example:
boolean result = 1.2003004005006007008009 > 1.2003004005006007008008;
System.out.println(result);
Prints false, even though mathematically the first number is larger than the second number (so you'd expect it to print true).
In conclusion: by using floating-point literal values, you won't suddenly have arbitrary-precision floating-point numbers.
I don't know why this happens:
float flo = 196.7f;
BigDecimal bd = new BigDecimal(flo);
System.out.println(bd); //print 196.6999969482421875
BigDecimal bd2 = new BigDecimal(Float.toString(flo));
System.out.println(bd2); //print 196.7
Both your questions are clearly stated in the Javadoc.
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a
BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with
a scale of 1), but it is actually equal to
0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that
matter, as a binary fraction of any finite length). Thus, the value
that is being passed in to the constructor is not exactly equal to
0.1, appearances notwithstanding.
The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which
is exactly equal to 0.1, as one would expect. Therefore, it is
generally recommended that the String constructor be used in
preference to this one.
This question already has answers here:
Test for floating point equality. (FE_FLOATING_POINT_EQUALITY)
(3 answers)
Why does Double.NaN==Double.NaN return false?
(10 answers)
Closed 9 years ago.
I am reading Effective java by Joshua Bloch and in Item 8: Obey the general contract when overriding equals, this statement is written
for float fields, use the Float.compare method; and for double fields, use
Double.compare. The special treatment of float and double fields is made
necessary by the existence of Float.NaN, -0.0f and the analogous double
constants;
Can someone explain me with example why we can't use == for float or double comparison
From apidoc, Float.compare:
Compares the two specified float values. The sign of the integer value returned is the same as that of the integer that would be returned by the call:
new Float(f1).compareTo(new Float(f2))
Float.compareTo:
Compares two Float objects numerically. There are two ways in which comparisons performed by this method differ from those performed by the Java language numerical comparison operators (<, <=, ==, >= >) when applied to primitive float values:
Float.NaN is considered by this method to be equal to itself and greater than all other float values (including Float.POSITIVE_INFINITY).
0.0f is considered by this method to be greater than -0.0f.
This ensures that the natural ordering of Float objects imposed by this method is consistent with equals.
Consider the following code:
System.out.println(-0.0f == 0.0f); //true
System.out.println(Float.compare(-0.0f, 0.0f) == 0 ? true : false); //false
System.out.println(Float.NaN == Float.NaN);//false
System.out.println(Float.compare(Float.NaN, Float.NaN) == 0 ? true : false); //true
System.out.println(-0.0d == 0.0d); //true
System.out.println(Double.compare(-0.0d, 0.0d) == 0 ? true : false);//false
System.out.println(Double.NaN == Double.NaN);//false
System.out.println(Double.compare(Double.NaN, Double.NaN) == 0 ? true : false);//true
The ouput is not correct, since something that is not a number, is simply not a number, and should be treated as equal from number comparison point of view. It is also clear that 0=-0.
Let's see what Float.compare does:
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1; // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1; // Neither val is NaN, thisVal is larger
int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
Float.floatToIntBits:
Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout.
Bit 31 (the bit that is selected by the mask 0x80000000) represents the sign of the floating-point number. Bits 30-23 (the bits that are selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the bits that are selected by the mask 0x007fffff) represent the significand (sometimes called the mantissa) of the floating-point number.
If the argument is positive infinity, the result is 0x7f800000.
If the argument is negative infinity, the result is 0xff800000.
If the argument is NaN, the result is 0x7fc00000.
In all cases, the result is an integer that, when given to the intBitsToFloat(int) method, will produce a floating-point value the same as the argument to floatToIntBits (except all NaN values are collapsed to a single "canonical" NaN value).
From JLS 15.20.1. Numerical Comparison Operators <, <=, >, and >=
The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:
If either operand is NaN, then the result is false.
All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.
Positive zero and negative zero are considered equal. For example, -0.0<0.0 is false, but -0.0<=0.0 is true.
Note, however, that the methods Math.min and Math.max treat negative zero as being strictly smaller than positive zero.
For strict comparisons where operands are positive zero and negative zero the result will be wrong.
From JLS 15.21.1. Numerical Equality Operators == and !=:
The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:
Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:
If either operand is NaN, then the result of == is false but the result of != is true. Indeed, the test x!=x is true if and only if the value of x is NaN. The methods Float.isNaN and Double.isNaN may also be used to test whether a value is NaN.
Positive zero and negative zero are considered equal. For example, -0.0==0.0 is true.
Otherwise, two distinct floating-point values are considered unequal by the equality operators. In particular, there is one value representing positive infinity and one value representing negative infinity; each compares equal only to itself, and each compares unequal to all other values.
For equality comparisons where both operands are NaN the result will be wrong.
Since total ordering (=, <, >,<=, >=) is used by many important algorithms (see all the classes that implement the Comparable interface) it is better to use the compare method because it will yield more consistent behavior.
The consequence of the total ordering in the context of the IEEE-754 standard is the difference between the positive and negative zero.
For instance, if you use the equality operator instead of the compare method, and have some collection of values and your code logic makes some decisions based on the ordering of the elements, and you somehow start getting a surplus of NaN values they'll all be treated as different values instead as the same values.
That may likely produce error in the behavior of the program proportional to the amount/rate of NaN values. And if you have a lot of positive and negative zeroes, that's just one pair to affect your logic with error.
Float uses IEEE-754 32 bit format and Double uses IEEE-754 64 bit format.
float (and double) have some special bit sequences that are reserved for special meanings that are not "numbers":
Negative infinity, internal representation 0xff800000
Positive infinity, internal representation 0x7f800000
Not a Number, internal representation 0x7fc00000
Each of these returns 0 (meaning they are "the same") when compared to itself using Float.compare(), but the following comparisons using == differ from this for Float.NaN:
Float.NEGATIVE_INFINITY == Float.NEGATIVE_INFINITY // true
Float.POSITIVE_INFINITY == Float.POSITIVE_INFINITY // true
Float.NaN == Float.NaN // false
So when comparing float values, to be consistent for all values, including the special Float.NaN value, Float.compare() is the best option.
The same applies to double.
There are two reasons to compare floating-point objects:
I am doing math, so I want to compare their numerical values. Numerically, –0 equals +0, and a NaN is not equal to anything, not even itself, because “equal” is a property that only numbers have, and NaN is not a number.
I am working with objects in a computer, so I need to distinguish different objects and place them in order. This is necessary for sorting objects in a tree or other container, for example.
The == operator provides mathematical comparisons. It returns false for NaN == NaN and true for -0.f == +0.f
The compare and compareTo routines provide object comparisons. When comparing a NaN to itself, they indicate that it is the same (by returning zero). When comparing -0.f to +0.f, they indicate they are different (by returning non-zero).
I am looking for the best way to convert a Number to a BigDecimal.
Is this good enough?
Number number;
BigDecimal big = new BigDecimal(number.toString());
Can we lose precision with the toString() method ?
This is fine, remember that using the constructor of BigDecimal to declare a value can be dangerous when it's not of type String. Consider the below...
BigDecimal valDouble = new BigDecimal(0.35);
System.out.println(valDouble);
This will not print 0.35, it will infact be...
0.34999999999999997779553950749686919152736663818359375
I'd say your solution is probably the safest because of that.
Can we lose precision with toString() method ?
Kind of ... Both Float.toString() and Double.toString() only output the number of digits after the decimal separator, which is required for the output uniquely to correspond to a float or double value.
To use the 0.35 example in david99world's answer, consider the following code:
BigDecimal bd1 = new BigDecimal(0.35);
Number n = 0.35;
BigDecimal bd2 = new BigDecimal(n.toString());
System.out.println(bd1);
System.out.println(bd2);
An intuitive expectation may be that the two BigDecimal instances are identical, but the output shows that they are not:
0.34999999999999997779553950749686919152736663818359375
0.35
The first line is the exact value of the double, since 0.35 cannot be represented exactly. The second line is 0.35, since no more fractional digits are required to represent the distinct value. E.g. the statement 0.34999999999999997779553950749686919152736663818359375 == 0.35 will evaluate to true.
This is actually not a loss of precision when creating the BigDecimal, the uncertainty is already there in your "source" value. The problem is rather that the discrete values possible using e.g. a float or double value as source not necessarily will be represented by the exact equivalent in the BigDecimal instance.
I think this is the best way to convert Number to BigDecimal:
public static BigDecimal convertToBigDecimal(Number number) {
if (number instanceof Integer
|| number instanceof Long
|| number instanceof Short
|| number instanceof Byte) {
return BigDecimal.valueOf(number.longValue());
}
return BigDecimal.valueOf(number.doubleValue());
}
For Number, your solution is probably the best.
For doubles, probably the best way is
BigDecimal.valueOf(myDouble);
It works also for longs and it's optimized for frequently used longs value.
Source
BigDecimal bd= new BigDecimal("00.0000000000");
//now bd format to 0E-10
if(BigDecimal.ZERO.equals(bd) || bd.equals("0E-10"))
{
flag=true;
}
There are two problems in the above code
why variable bd automatically format to 0E-10
if condition results false value, ie it does not enter inside if block.
Can anyone suggest. thanks
You've given the constructor ten digits after the decimal point, so even though all of them are zero, BigDecimal has decided to set its internal scale to 10. This explains the -10 in "0E-10".
As to equals, the Javadoc says:
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).
Bottom line:
Use compareTo() instead of equals().
Don't directly compare BigDecimal to String as this won't work.
You can test for zero using
bd.signum() == 0
BigDecimal.equals also includes scale (which is 10 in your case) and thus fails. In general you should use compareTo in order to compare BigDecimals.
The BigDecimal uses a scale of 10 because you've given it ten digits after the decimal point, which answers your first point.
For the if, for the first part, you are comparing 0 with 00.00000000000 (the scale is different, so they aren't the same). In the second, you're comparing a String with a BigDecimal. Which won't work.