Java BigDecimal difference - java

I wanted to see if anyone can explain why the following code works with valueOf but not others.
import java.math.BigDecimal;
public class Change {
public static void main(String args[]) {
double a = 4.00d;
double b = 3.10d;
BigDecimal a1 = new BigDecimal(a);
BigDecimal b1 = new BigDecimal(b);
BigDecimal diff = a1.subtract(b1);
System.out.println("Double difference");
System.out.println(diff);
float c = 4.00f;
float d = 3.10f;
BigDecimal a2 = new BigDecimal(c);
BigDecimal b2 = new BigDecimal(d);
BigDecimal diff2 = a2.subtract(b2);
System.out.println("Float difference");
System.out.println(diff2);
System.out.println("Valueof Difference");
System.out.println(BigDecimal.valueOf(4.00).subtract(BigDecimal.valueOf(3.10)));
}
}
The output looks like:
>java Change
Double difference
0.899999999999999911182158029987476766109466552734375
Float difference
0.900000095367431640625
Valueof Difference
0.9
My question is: What does valueOf() do to get the precision?
Is there any other way of getting the correct result without rounding off to the 2 digits manually?
thanks,

Looking at the source code for BigDecimal, it does:
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
From its JavaDoc:
Translates a double into a BigDecimal,
using the double's canonical string
representation provided by the
Double.toString(double) method.
Note: This is generally the preferred way to
convert a double (or float) into a
BigDecimal, as the value returned is
equal to that resulting from
constructing a BigDecimal from the
result of using
Double.toString(double).
Because of floating-point representation, a double value is not exactly what you set it as. However, during String representation, it rounds off what it displays. (All of the rules are on it's JavaDoc).
Furthermore, because of this rounding, if you did:
BigDecimal d = BigDecimal.valueOf(4.00000000000000000000000000000000001));
you would get the wrong value. (d == 4.0)
So, it's pretty much always better to initialize these with strings.

BigDecimal.valueOf(double) first does a conversion from double to String, then String to BigDecimal.
In the first case, you're starting with a double or float, converting to BigDecimal, calculating the difference. In the second case, you're starting with double or float, converting to a String, then converting to BigDecimal, then calculating the difference.

From the Javadocs:
public static BigDecimal valueOf(double val)
Translates a double into a BigDecimal,
using the double's canonical string
representation provided by the
Double.toString(double) method. Note:
This is generally the preferred way to
convert a double (or float) into a
BigDecimal, as the value returned is
equal to that resulting from
constructing a BigDecimal from the
result of using
Double.toString(double).
I think this answers both of your questions.
Cheers,

The valueOf works because it calls Double.toString. from the Javadoc:
public static BigDecimal valueOf(double val)
Translates a double into a BigDecimal, using the double's
canonical string representation
provided by the
Double.toString(double) method.
When you pass a double into the BigDecimal constructor, the constructor takes the floating-point value and reproduces it exactly. The toString code finds an approximation for the floating point value.
In case you didn't notice, using System.out.println() to show a floating point number doesn't show the same results as if you wrap the floating point number in a BigDecimal first (using the BigDecimal constructor that takes a double).

Related

Is there a better way to convert a Double to it's exact decimal String?

I tried many ways to convert a Double to it's exact decimal String with String.format() and DecimalFormater and I found this so far :
String s = "-.0000000000000017763568394002505";
Double d = Double.parseDouble(s) * 100;
System.out.println((new java.text.DecimalFormat("###########################.################################################################################")).format(d));
(https://ideone.com/WG6zeC)
I'm not really a fan of my solution because it's ugly to me to make a huge pattern that does not covers all the cases.
Do you have another way to make this ?
I really want to have ALL the decimals, without scientific notation, without trailing zeros.
Thanks
P.S.: I need this without external libraries and in Java 1.7.
Seems as if you have to deal with some precision. double is not intended for this use. Better use BigDecimal
String value="13.23000";
BigDecimal bigD=new BigDecimal(value);
System.out.println(bigD);
System.out.println(bigD.stripTrailingZeros().toPlainString());
There is a big difference between new BigDecimal("0.1") and new BigDecimal(0.1). Using the String constructor can result in trailing zeros, and loses the effects of rounding to double on parsing the string. If the objective is to print the exact value of the double, you need to use BigDecimal's double constructor. Do any arithmetic in double, not BigDecimal.
import java.math.BigDecimal;
public class Test {
public static void main(String[] args) {
String s = "-.0000000000000017763568394002505";
double d = Double.parseDouble(s) * 100;
System.out.println(new BigDecimal(d).toPlainString());
}
}
Try this code:
You can also use toString() method, but it uses scientific notation.
https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#toPlainString()
BigDecimal bd = new BigDecimal("-.0000000000000017763568394002505");
System.out.println(bd.toPlainString());

Convert string to BigDecimal in java

I am reading a currency from XML into Java.
String currency = "135.69";
When I convert this to BigDecimal I get:
System.out.println(new BigDecimal(135.69));
Output:
135.68999999999999772626324556767940521240234375.
Why is it that it outputs this many numbers? How can I avoid this? All I want is for it to output 135.69.
The BigDecimal(double) constructor can have unpredictable behaviors. It is preferable to use BigDecimal(String) or BigDecimal.valueOf(double).
System.out.println(new BigDecimal(135.69)); //135.68999999999999772626324556767940521240234375
System.out.println(new BigDecimal("135.69")); // 135.69
System.out.println(BigDecimal.valueOf(135.69)); // 135.69
The documentation for BigDecimal(double) explains in detail:
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.
When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give
the same result as converting the double to a String using the
Double.toString(double) method and then using the BigDecimal(String)
constructor. To get that result, use the static valueOf(double)
method.
String currency = "135.69";
System.out.println(new BigDecimal(currency));
//will print 135.69
You are storing 135.69 as String in currency. But instead of passing variable currency, you are again passing 135.69(double value) into new BigDecimal().
So you are seeing a lot of numbers in the output.
If you pass the currency variable, your output will be 135.69
May I add something. If you are using currency you should use Scale(2), and you should probably figure out a round method.
BigDecimal b = BigDecimal.valueOf(d);
import java.math.*;
public class Test {
public static void main(String[] args)
{
// Creating a Double Object
Double d = new Double("785.254");
/// Assigning the bigdecimal value of ln to b
BigDecimal b = BigDecimal.valueOf(d);
// Displaying BigDecimal value
System.out.println("The Converted BigDecimal value is: " + b);
}
}
Spring Framework provides an excellent utils class for achieving this.
Util class : NumberUtils
String to BigDecimal conversion -
NumberUtils.parseNumber("135.00", BigDecimal.class);
Hi Guys you cant convert directly string to bigdecimal
you need to first convert it into long after that u will convert big decimal
String currency = "135.69";
Long rate1=Long.valueOf((currency ));
System.out.println(BigDecimal.valueOf(rate1));

How to limit BigDecimal to a fixed fractions amount?

I'm trying to create a BigDecimal class that has always a fixed maximum fractions count.
But when printing that number, it is not cut to the fractions I defined in scale. Why?
class MyDecimal extends BigDecimal {
public MyDecimal(double val) {
super(val);
setScale(4, RoundingMode.HALF_UP);
}
}
Sysout(new MyDecimal(0.0001));
//0.000100000000000000008180305391403130954586231382563710212707519531254
BigDecimal is immutable, and should not be extended. setScale() does not modify the BigDecimal instance. It returns a copy of the BigDecimal instance with the scale modified (as every other "mutating" method of BigDecimal, since it's immutable). Calling it and ignoring the returned value is thus useless.
Instead of extending BigDecimal, create a factory method:
public static BigDecimal createWithScale4(double d) {
BigDecimal temp = new BigDecimal(d);
return temp.setScale(4);
}
The problem is that you are putting in your input as a double. This is from 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
Since you are using a double, it is being stored as a floating-point number, and not as a precision number. It then converts that non-precision floating-point number to a precision BigDecimal, which then puts it out as a precise number. It works if the input is a String, however, since a String is just text, and converts the string directly to a BigDecimal. See this from here:
Creating a big decimal from a (scalar) double is simple:
bd = new BigDecimal(1.0);
To get a BigDecimal from a Double, get its
doubleValue() first.
However it is a good idea to use the string constructor:
bd = new BigDecimal("1.5");
If you don't, then you'll get the following,
bd = new BigDecimal(1.5);
bd.toString(); // => 0.1499999999999999944488848768742172978818416595458984375
So do it like this:
Sysout(new MyDecimal("0.0001"));
Also, as #JBNizet points out, you're extending an immutable object, a BigDecimal. You're ignoring the return value of setting the scale. This could be changed by using a method such as the one below:
public static BigDecimal createBigDecimal(String s) {
BigDecimal bigdeci = new BigDecimal(s);
return bigdeci.setScale(4);
}
The problem is that you're passing the argument as a double instead of as a string. Before the argument reaches the Big Decimal, it has already been converted into binary form to store as a double, which introduces a tiny error (it's equivalent to trying to write 1/3 as a decimal and getting 0.3333333333; it won't be quite right unless you have infinite precision).
Instead, try:
Sysout((new BigDecimal("0.0001")).setScale(4,RoundingMode.HALF_UP));

Convert double to BigDecimal and set BigDecimal Precision

In Java, I want to take a double value and convert it to a BigDecimal and print out its String value to a certain precision.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
double d=-.00012;
System.out.println(d+""); //This prints -1.2E-4
double c=47.48000;
BigDecimal b = new BigDecimal(c);
System.out.println(b.toString());
//This prints 47.47999999999999687361196265555918216705322265625
}
}
It prints this huge thing:
47.47999999999999687361196265555918216705322265625
and not
47.48
The reason I'm doing the BigDecimal conversion is sometimes the double value will contain a lot of decimal places (i.e. -.000012) and the when converting the double to a String will produce scientific notation -1.2E-4. I want to store the String value in non-scientific notation.
I want to have BigDecimal always have two units of precision like this: "47.48". Can BigDecimal restrict precision on conversion to string?
The reason of such behaviour is that the string that is printed is the exact value - probably not what you expected, but that's the real value stored in memory - it's just a limitation of floating point representation.
According to javadoc, BigDecimal(double val) constructor behaviour can be unexpected if you don't take into consideration this limitation:
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.
So in your case, instead of using
double val = 77.48;
new BigDecimal(val);
use
BigDecimal.valueOf(val);
Value that is returned by BigDecimal.valueOf is equal to that resulting from invocation of Double.toString(double).
It prints 47.48000 if you use another MathContext:
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64);
Just pick the context you need.
You want to try String.format("%f", d), which will print your double in decimal notation. Don't use BigDecimal at all.
Regarding the precision issue: You are first storing 47.48 in the double c, then making a new BigDecimal from that double. The loss of precision is in assigning to c. You could do
BigDecimal b = new BigDecimal("47.48")
to avoid losing any precision.
Why not :
b = b.setScale(2, RoundingMode.HALF_UP);
It's printing out the actual, exact value of the double.
Double.toString(), which converts doubles to Strings, does not print the exact decimal value of the input -- if x is your double value, it prints out exactly enough digits that x is the closest double to the value it printed.
The point is that there is no such double as 47.48 exactly. Doubles store values as binary fractions, not as decimals, so it can't store exact decimal values. (That's what BigDecimal is for!)
The String.format syntax helps us convert doubles and BigDecimals to strings of whatever precision.
This java code:
double dennis = 0.00000008880000d;
System.out.println(dennis);
System.out.println(String.format("%.7f", dennis));
System.out.println(String.format("%.9f", new BigDecimal(dennis)));
System.out.println(String.format("%.19f", new BigDecimal(dennis)));
Prints:
8.88E-8
0.0000001
0.000000089
0.0000000888000000000
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
In Java 9 the following is deprecated:
BigDecimal.valueOf(d).setScale(2, BigDecimal.ROUND_HALF_UP);
instead use:
BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
Example:
double d = 47.48111;
System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111
BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
System.out.println(bigDecimal); //Prints: 47.48

How to convert from float to bigDecimal in java?

How to convert from float to bigDecimal in java?
BigDecimal value = new BigDecimal(Float.toString(123.4f));
From the javadocs, the string constructor is generally the preferred way to convert a float into a BigDecimal, as it doesn't suffer from the unpredictability of the BigDecimal(double) constructor.
Quote from the docs:
Note: For values other float and double NaN and ±Infinity, this constructor is compatible with the values returned by Float.toString(float) and Double.toString(double). This is generally the preferred way to convert a float or double into a BigDecimal, as it doesn't suffer from the unpredictability of the BigDecimal(double) constructor.
float f = 45.6f;
BigDecimal bd = BigDecimal.valueOf(f);
Quote from documentations:
Note: This is generally the preferred way to convert a double (or
float) into a BigDecimal, as the value returned is equal to that
resulting from constructing a BigDecimal from the result of using
Double.toString(double).
Reference: BigDecimal (Java Platform SE 6)
For a precision of 3 digits after the decimal point:
BigDecimal value = new BigDecimal(f,
new MathContext(3, RoundingMode.HALF_EVEN));
This is upto my knowledge :
public static BigDecimal floatToBigDecimal(Float a){
if(a == null || a.isInfinite() || a.isNaN()){
return BigDecimal.ZERO;
}
try{
return BigDecimal.valueOf(a);
}catch(Exception e){
return BigDecimal.ZERO;
}
}
*Note:This is generally the preferred way to convert a double (or float) into a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal from the result of using Double.toString(double).
public static BigDecimal valueOf(double val)
Parameters:
val - double to convert to a BigDecimal.
Returns:
a BigDecimal whose value is equal to or approximately equal to the value of val.
Throws:
NumberFormatException - if val is infinite or NaN.
Since:
1.5
I have checked whether Infinite or Not a Number, so that there is less chances of NumberFormatException

Categories

Resources