How to preserve precision of Bigdecimal in Java? - java

I am using xs:decimal as Type in XSD with length as
value="9999999999999999.999999999999999"
BigDecimal big = new BigDecimal("0.000000000001");
System.out.println(big); // Actual 1e-12 Expected 0.000000000001
i cannot use toPlainString(), since i want it in BigDecimal

From the javadoc : BigDecimal.toPlainString
public String toPlainString()
Returns a string representation of this BigDecimal without an exponent field.
BigDecimal bd = new BigDecimal("0.000000001");
System.out.println(bd);
System.out.println(bd.toPlainString());
Will output :
1E-9
0.000000001

Related

Java float formatting issue

I retrieve from an XML file a float number that I want to format and insert in a text file with the pattern 8 digits after comma, and 2 before.
Here is my code:
String patternNNDotNNNNNNNN = "%11.8f";
float value = 1.70473711f;
String result = String.format(java.util.Locale.US, patternNNDotNNNNNNNN, value);
System.out.println(result);
As a result I get: 1.70473707
Same problem if I use:
java.text.DecimalFormatSymbols symbols = new java.text.DecimalFormatSymbols(java.util.Locale.US);
java.text.DecimalFormat df = new java.text.DecimalFormat("##.########", symbols);
System.out.println(df.format(value));
I don't understand why I have a rounded value (1.70473711 comes to 1.70473707).
This is because the precision of the float means that the value 1.7043711 is not actually 1.7043711.
Consider the following which process 1.70473711f as both a float and a double:
String patternNNDotNNNNNNNN = "%11.8f";
float valueF = 1.70473711f;
String result = String.format(java.util.Locale.US, patternNNDotNNNNNNNN, valueF);
System.out.println(valueF);
System.out.println(result);
double valueD = 1.70473711f;
result = String.format(java.util.Locale.US, patternNNDotNNNNNNNN, valueD);
System.out.println(valueD);
System.out.println(result);
Output:
1.7047371
1.70473707
1.7047370672225952
1.70473707
When treating the value as a double, you can see that 1.7043711f is actually 1.7047370672225952. Rounding that to 8 places gives 1.70473707 and not 1.70473711 as expected.
Instead, treat the number as a double (i.e. remove the f) and the increase precision will result in the expected output:
double valueD = 1.70473711;
String result = String.format(java.util.Locale.US, patternNNDotNNNNNNNN, valueD);
System.out.println(valueD);
System.out.println(result);
Output:
1.70473711
1.70473711
String.format on floating point values does round them. If you don't want that, use BigDecimal. See
double d = 0.125;
System.out.printf("%.2f%n", d);

How to retain trailing zeroes when converting BigDecimal to String

I have to convert a BigDecimal value, e.g. 2.1200, coming from the database to a string. When I use the toString() or toPlainString() of BigDecimal, it just prints the value 2.12 but not the trailing zeroes.
How do I convert the BigDecimal to string without losing the trailing zeroes?
try this..
MathContext mc = new MathContext(6); // 6 precision
BigDecimal bigDecimal = new BigDecimal(2.12000, mc);
System.out.println(bigDecimal.toPlainString());//2.12000
To convert a BigDecimal to a String with a particular pattern you need to use a DecimalFormat.
BigDecimal value = .... ;
String pattern = "#0.0000"; // If you like 4 zeros
DecimalFormat myFormatter = new DecimalFormat(pattern);
String output = myFormatter.format(value);
System.out.println(value + " " + pattern + " " + output);
To check the possible values of pattern see here DecimalFormat
double value = 1.25;
// To convet double to bigdecimal
BigDecimal bigDecimalValue = BigDecimal.valueOf(value);
//set 4 trailing value
BigDecimal tempValue = bigDecimalValue.setScale(4, RoundingMode.CEILING);
System.out.println(tempValue.toPlainString());
You can use below code .
BigDecimal d = new BigDecimal("1.200");
System.out.println(d);
System.out.println(String.valueOf(d));
Output is as below :
1.200
1.200
In a practical way, just don't use BigDecimal, instead use toString() of Double class.

Remove Decimals from String

I have a function that converst a BigDecimal into a String plus the currency. When I use this the number (e.g. 34) turns into a number with a lot of decimals (e.g. 34.000000).
What can I do to solve this and just show the 34?
Here is my function:
row.put("Money", GcomNullPointerValidator.isNullField(formatUtils.formatCurrency(MoneyDto.getAmount().stripTrailingZeros())));
What is the language? Java?
You can use the split() function of String if you just want to keep numbers before "." :
String mystring = "34.000000";
String correctstring[] = mystring.split(".");
System.out.println(correctstring[0]);
// display : 34
it will delete all digits after "." !
Inside your method that converts a BigDecimal into a String, you can use BigDecimal.setScale() to set the number of digits after the decimal point. For example:
BigDecimal d = new BigDecimal("34.000000");
BigDecimal d1 = d.setScale(2, BigDecimal.ROUND_HALF_UP); // yields 34.00
BigDecimal d2 = d.setScale(0, BigDecimal.ROUND_HALF_UP); // yields 34
You can use this:
String number = "150.000";
number.replaceAll("\\.\\d+$", "");
Or you can use this:
number.split(Pattern.quote("."))[0];

Truncate the fractional part of a BigDecimal when its scale is zero in Java

I need to remove the fractional part of a BigDecimal value when its scale has a value of zero. For example,
BigDecimal value = new BigDecimal("12.00").setScale(2, RoundingMode.HALF_UP);
It would assign 12.00. I want it to assign only 12 to value in such cases.
BigDecimal value = new BigDecimal("12.000000").setScale(2, RoundingMode.HALF_UP);
should assign 12,
BigDecimal value = new BigDecimal("12.0001").setScale(2, RoundingMode.HALF_UP);
should assign 12.
BigDecimal value = new BigDecimal("12.0051").setScale(2, RoundingMode.HALF_UP);
should assign12.01
BigDecimal value = new BigDecimal("00.000").setScale(2, RoundingMode.HALF_UP);
should assign 0.
BigDecimal value = new BigDecimal("12.3456").setScale(2, RoundingMode.HALF_UP);
should assign 12.35 and alike. Is this possible? What is the best way to do?
For the crosslink from there: https://codereview.stackexchange.com/questions/24299/is-this-the-way-of-truncating-the-fractional-part-of-a-bigdecimal-when-its-scale
Is this possible? What is the best way to do?
Probably stripTrailingZeros().
To check your tests:
public static void main(final String[] args) {
check(truncate("12.000000"), "12");
check(truncate("12.0001"), "12");
check(truncate("12.0051"), "12.01");
check(truncate("12.99"), "12.99");
check(truncate("12.999"), "13");
check(truncate("12.3456"), "12.35");
System.out.println("if we see this message without exceptions, everything is ok");
}
private static BigDecimal truncate(final String text) {
BigDecimal bigDecimal = new BigDecimal(text);
if (bigDecimal.scale() > 2)
bigDecimal = new BigDecimal(text).setScale(2, RoundingMode.HALF_UP);
return bigDecimal.stripTrailingZeros();
}
private static void check(final BigDecimal bigDecimal, final String string) {
if (!bigDecimal.toString().equals(string))
throw new IllegalStateException("not equal: " + bigDecimal + " and " + string);
}
output:
if we see this message without exceptions, everything is ok
The following code does what you specify with the help of regex and the construction of BigDecimal, it is probably not the most efficient way to go about:
BigDecimal value = new BigDecimal("12.0000").setScale(2, RoundingMode.HALF_UP);
Pattern pattern = Pattern.compile("\\d+\\.(\\d)0");
Matcher matcher = pattern.matcher(value.toString());
if (matcher.find()) {
if (matcher.group(1).equals("0"))
value = value.setScale(0);
else
value = value.setScale(1);
}
Note: this also makes 12.100 -> 12.1, I assume that is wanted functionality.
Instead of modifying the original value on my own by hand, I have simply tried to apply some conditions like,
String text="123.008";
BigDecimal bigDecimal=new BigDecimal(text);
if(bigDecimal.scale()>2)
{
bigDecimal=new BigDecimal(text).setScale(2, RoundingMode.HALF_UP);
}
if(bigDecimal.remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO)==0)
{
bigDecimal=new BigDecimal(text).setScale(0, BigDecimal.ROUND_HALF_UP);
}
System.out.println("bigDecimal = "+bigDecimal);
The first if condition checks, if the scale is greater than 2. If so, then perform the rounding operation as specified.
The next if condition checks, if the value of the fractional part yields zero. If so, then truncate it. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by the compareTo() method. Therefore, the condition is satisfied whenever the the value of the fractional part is evaluated to zero.
Otherwise, the original value is left untouched (if the scale is either 1 or 2).
If I'm missing something or it's a wrong thing to implement, then please clarify it.
Try this one:
new BigDecimal("12.3456").setScale(2, RoundingMode.FLOOR).stripTrailingZeros()

BigDecimal to string

I have a BigDecimal object and i want to convert it to string.
The problem is that my value got fraction and i get a huge number (in length) and i only need the original number in string for example:
for
BigDecimal bd = new BigDecimal(10.0001)
System.out.println(bd.toString());
System.out.println(bd.toPlainString());
the output is:
10.000099999999999766941982670687139034271240234375
10.000099999999999766941982670687139034271240234375
and i need the out put to be exactly the number 10.0001 in string
To get exactly 10.0001 you need to use the String constructor or valueOf (which constructs a BigDecimal based on the canonical representation of the double):
BigDecimal bd = new BigDecimal("10.0001");
System.out.println(bd.toString()); // prints 10.0001
//or alternatively
BigDecimal bd = BigDecimal.valueOf(10.0001);
System.out.println(bd.toString()); // prints 10.0001
The problem with new BigDecimal(10.0001) is that the argument is a double and it happens that doubles can't represent 10.0001 exactly. So 10.0001 is "transformed" to the closest possible double, which is 10.000099999999999766941982670687139034271240234375 and that's what your BigDecimal shows.
For that reason, it rarely makes sense to use the double constructor.
You can read more about it here, Moving decimal places over in a double
Your BigDecimal doesn't contain the number 10.0001, because you initialized it with a double, and the double didn't quite contain the number you thought it did. (This is the whole point of BigDecimal.)
If you use the string-based constructor instead:
BigDecimal bd = new BigDecimal("10.0001");
...then it will actually contain the number you expect.
For better support different locales use this way:
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(0);
df.setGroupingUsed(false);
df.format(bigDecimal);
also you can customize it:
DecimalFormat df = new DecimalFormat("###,###,###");
df.format(bigDecimal);
By using below method you can convert java.math.BigDecimal to String.
BigDecimal bigDecimal = new BigDecimal("10.0001");
String bigDecimalString = String.valueOf(bigDecimal.doubleValue());
System.out.println("bigDecimal value in String: "+bigDecimalString);
Output:
bigDecimal value in String: 10.0001
// Convert BigDecimal number To String by using below method //
public static String RemoveTrailingZeros(BigDecimal tempDecimal)
{
tempDecimal = tempDecimal.stripTrailingZeros();
String tempString = tempDecimal.toPlainString();
return tempString;
}
// Recall RemoveTrailingZeros
BigDecimal output = new BigDecimal(0);
String str = RemoveTrailingZeros(output);
If you just need to set precision quantity and round the value, the right way to do this is use it's own object for this.
BigDecimal value = new BigDecimal("10.0001");
value = value.setScale(4, RoundingMode.HALF_UP);
System.out.println(value); //the return should be "10.0001"
One of the pillars of Oriented Object Programming (OOP) is "encapsulation", this pillar also says that an object should deal with it's own operations, like in this way:
The BigDecimal can not be a double.
you can use Int number.
if you want to display exactly own number, you can use the String constructor of BigDecimal .
like this:
BigDecimal bd1 = new BigDecimal("10.0001");
now, you can display bd1 as 10.0001
So simple.
GOOD LUCK.
To archive the necessary result with double constructor you need to round the BigDecimal before convert it to String e.g.
new java.math.BigDecimal(10.0001).round(new java.math.MathContext(6, java.math.RoundingMode.HALF_UP)).toString()
will print the "10.0001"

Categories