BigDecimal RoundingMode.HALF_UP doesn't work as expected [duplicate] - java

I have a BigDecimal defined like this:
private static final BigDecimal sd = new BigDecimal(0.7d);
if i print it, i get the value:
0.6999999999999999555910790149937383830547332763671875
which causes some wrong calculations. Does anyone know a way to get the exact value of 0.7 as BigDecimal? Change it to 0.71 would view the right result, but it shouldn't be like that

Use a String literal:
private static final BigDecimal sd = new BigDecimal("0.7");
If you use a double, actually public BigDecimal(double val) is called. The reason you do not get 0.7 is that it cannot be exactly represented by a double. See the linked JavaDoc for more information.

Perhaps if you bothered to read the documentation, i.e. the javadoc of the constructor you're using, you'd already know the answer.
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.
When you then look at the javadoc of BigDecimal.valueOf(double), you'll find:
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).
So there is your answer: Use BigDecimal.valueOf(0.7d), not new BigDecimal(0.7d).

You should use the declared value in String literal such as new BigDecimal("0.7");

Here are three ways:
private static final BigDecimal sd = new BigDecimal("0.7");
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL32);
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL64)

Constructing a BigDecimal from a double is surprisingly complicated. First, it can only be done via the detour of a string. (You can't get the constructor with double and a MathContext right. I've tried a lot. At the latest in cases in which the number of places before the decimal point would need to change due to rounding, it becomes difficult. Hence the warning in the Javadoc that you shouldn’t use it.)
However, even there, it is not enough with a simple String.format(), since String.format() is sensitive to the default Locale and outputs different decimal separators depending on system/VM settings, while the BigDecimal constructor always requires a dot as a decimal separator. So you have to construct your own Formatter with Locale.US. If you have this up and running, you will get a warning of an unclosed resource.
I found this to work:
static BigDecimal toBigDecimal(double value, int decimalPlaces) {
String format = "%." + decimalPlaces + "f";
try (Formatter formatter = new Formatter(Locale.US)) {
String formatted = formatter.format(format, value).toString();
return new BigDecimal(formatted);
}
}

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());

BigDecimal adding wrong value

I have a BigDecimal defined like this:
private static final BigDecimal sd = new BigDecimal(0.7d);
if i print it, i get the value:
0.6999999999999999555910790149937383830547332763671875
which causes some wrong calculations. Does anyone know a way to get the exact value of 0.7 as BigDecimal? Change it to 0.71 would view the right result, but it shouldn't be like that
Use a String literal:
private static final BigDecimal sd = new BigDecimal("0.7");
If you use a double, actually public BigDecimal(double val) is called. The reason you do not get 0.7 is that it cannot be exactly represented by a double. See the linked JavaDoc for more information.
Perhaps if you bothered to read the documentation, i.e. the javadoc of the constructor you're using, you'd already know the answer.
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.
When you then look at the javadoc of BigDecimal.valueOf(double), you'll find:
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).
So there is your answer: Use BigDecimal.valueOf(0.7d), not new BigDecimal(0.7d).
You should use the declared value in String literal such as new BigDecimal("0.7");
Here are three ways:
private static final BigDecimal sd = new BigDecimal("0.7");
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL32);
private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL64)
Constructing a BigDecimal from a double is surprisingly complicated. First, it can only be done via the detour of a string. (You can't get the constructor with double and a MathContext right. I've tried a lot. At the latest in cases in which the number of places before the decimal point would need to change due to rounding, it becomes difficult. Hence the warning in the Javadoc that you shouldn’t use it.)
However, even there, it is not enough with a simple String.format(), since String.format() is sensitive to the default Locale and outputs different decimal separators depending on system/VM settings, while the BigDecimal constructor always requires a dot as a decimal separator. So you have to construct your own Formatter with Locale.US. If you have this up and running, you will get a warning of an unclosed resource.
I found this to work:
static BigDecimal toBigDecimal(double value, int decimalPlaces) {
String format = "%." + decimalPlaces + "f";
try (Formatter formatter = new Formatter(Locale.US)) {
String formatted = formatter.format(format, value).toString();
return new BigDecimal(formatted);
}
}

How to convert String to BigDecimal without scientific notation

I am trying to convert String value to BigDecimal value.
when i use 0.000001234 I am getting same value in BigDecimal. But, when I use 0.000000123 or 0.000000012 I am getting 1.23E-7 or 1.2E-8.
I need like below,
if input is String = 0.000000123
Then output should be,
BigDecimal = 0.000000123
Please help me
import java.math.BigDecimal;
public class DecimalEx {
public static void main(String args[]){
String s = "0.000000023";
BigDecimal big = new BigDecimal(s);
System.out.println(big);
}
}
You're converting the String to a BigDecimal with no problems. The BigDecimal value has no notion of whether the value has exponential notation or not... it's just a scaled value.
The problem you're seeing is when you implicitly call BigDecimal.toString(), which is documented to use exponential notation sometimes:
If the scale is greater than or equal to zero and the adjusted exponent is greater than or equal to -6, the number will be converted to a character form without using exponential notation.
Instead, you want to use BigDecimal.toPlainString():
Returns a string representation of this BigDecimal without an exponent field.
Just change your last line of code to:
System.out.println(big.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));

Java BigDecimal difference

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).

Categories

Resources