BigDecimal Java. How to append zeros in front - java

My question is basically the following:
When I use a value with BigDecimal, how do I append zeros in front of a random number?
Say I want to have a number <10 following an entirely random pattern. Now i want to add zeros in front of the number, so the actual amount adds up to 10 numbers.
Here's an example:
BigDecimal num = new BigDecimal(2353);
Now I want to have that ouput:
0000002353
Is there a function that appends numbers to a BigDecimal type?
I couldn't find any.
I tried using a while loop that checks whether the number is less than ten. But I don't understand the Big Decimal well enough to actually compare integral values to the BigDecimal types.
Thanks for any help in advance!

If you use a BigInteger instead (or any integer type, such as int or long) you can format the value with
String.format("%010d", BigInteger.valueOf(2353))
The leading 0 in the format strings means pad with 0, the following 10 is the desired length...

BigDecimal is meant to be used for storing large floating point numbers. Since in a floating-point number there isn't any difference between 0000002353 and 2353, there is no reasonable way to append leading 0's to a BigDecimal just as there is no reasonable way to append leading 0's to a normal float. According to the behavior you're looking for, I would suggest using a String to store your number, and then convert to and from BigDecimal when you want to perform any operations.
To compare an integral type to a BigDecimal, first convert the variable to a BigDecimal and then call BigDecimal's compareTo method. More info is in this question.

Since you're interested in formatting the number, you might want to look at DecimalFormat class, which allows to format floating point and integer numbers according to the specified pattern.
BigDecimal num = new BigDecimal(2353);
DecimalFormat f1 = new DecimalFormat("0000000000");
DecimalFormat f2 = new DecimalFormat("0,000,000,000");
System.out.println(f1.format(num));
System.out.println(f2.format(num));
Output:
0000002353
0,000,002,353

If the maximum number of digits is 10 and only whole numbers are allowed you don't need anything more than to use long with standard formatting:
long myNumber = 123456;
System.out.printf("%010d%n", myNumber);

Related

Why is BigDecimal returning an approximation of my large double in Java?

I'd like to round my large double so the first thing I decided to do, was to convert it into a BigDecimal in the following way.
BigDecimal amount = BigDecimal
.valueOf(getAmount())
.setScale(2, RoundingMode.HALF_UP);
System.out.println(amount);
In my example, getAmount() returns 123456789123123424113.31.
Therefore, I expect the exact same value to be printed out by my snippet.
Instead, I get the following value:
123456789123123430000.00
Can someone explain why BigDecimal is returning an approximation of my double?
In my example, getAmount() returns 123456789123123424113.31.
No, it does not. That is not a value that a double can represent exactly.
You can easily verify that with this code:
double d = 123456789123123424113.31d;
System.out.println(d);
Which outputs
1.2345678912312343E20
This value has the minimum amount of digits to uniquely distinguish it from any other double value. Meaning that there aren't any more relevant digits in that double. You've already lost the precision before converting the value to BigDecimal.
While an integer data type such as long and int can exactly represent every (integer) value within its range, the same can't be said about floating point numbers: they have an immense range of values that they can represent, but at the cost of not being able to represent every possible value within the range. Effectively there's a limited number of digits that a floating point number can represent (about 16 decimal digits for double and about 7 decimal digits for float). Everything else will be cut off.
If you need arbitrary precision then something like BigDecimal can help: it will allocate as much memory as necessary to hold all digits (or round according to your specification, if required), making it much more complex but also more powerful.
BigDecimal bd = new BigDecimal("123456789123123424113.31");
System.out.println(bd);
will print
123456789123123424113.31
Make sure not to initialize the BigDecimal from a double value, as you'll only get the cut-off value even then.

NumberFormat doesn't like more than 340 decimal places

I want to format a double with a certain number of decimal places in Java. My code currently looks like this:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(decimalPlaces);
format.setMaximumFractionDigits(decimalPlaces);
format.setGroupingUsed(false);
String s = format.format(value);
but when decimalPlaces is more than 340, this method just prints 340 digits and ignores the rest. Is there a way to work around this limitation?
Specifically in my case they're all 0s (and probably would be with any number after a certain point since the precision is not that high) but it seems wrong to me that the function just silently ignores what I want instead of throwing an exception or something.
Yes, I'm aware that a double can't actually hold that many decimal places, but it's also true that an int can't hold any decimal places at all yet I'm able to print it with some.
The documentation of setMinimumFractionDigits contains this statement:
The concrete subclass may enforce an upper limit to this value appropriate to the numeric type being formatted.
Most likely the subclass returned by NumberFormat.getInstance is DecimalFormat, which tells us in the JavaDocs
For formatting numbers other than BigInteger and BigDecimal objects, the lower of newValue and 340 is used. Negative input values are replaced with 0.
So to solve your problem, convert your number to a BigDecimal before formatting it.
In case of double the value is getting truncating. Use/declare value as BigDecimal
Try this sample code:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(355);
format.setMaximumFractionDigits(400);
format.setGroupingUsed(false);
System.out.println(format.getMinimumFractionDigits());
BigDecimal bd=new BigDecimal(10L);
String s = format.format(bd);
System.out.println(s.length());
System.out.println(s);

decimal points precision is lost for some munbers in case of double data type

I am suprise to see the below program please advise how it is behaving like this as i aam very much concerened with poitn to precison after decimal point , below is the progrmam
double fixedRate = 0.997500000000; //**output --->0.9975
// BigDecimal fixedRate = new BigDecimal("0.997500000000");
double fixedRate1 = 0.1234567890123456789;
System.out.println(fixedRate);
System.out.println(fixedRate1);
and the output is
0.9975
0.12345678901234568
now please advise for the first the ouput is 0.9975 but late on for next it is not truncating after decimal points but why for first then.
The precision is not lost. It is just not printed because you do not need more digits to distinguish the printed value from any other double value.
If you do want to force a certain number of fractional digits, take a look at System.out.printf() or String.format().
See https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html for more details and possible formats.
The result may look like this:
System.out.printf("%.19f%n",fixedRate);
System.out.printf("%.19f%n", fixedRate1);
This is a printing problem.Please use this format to print your values and tell me the result:
double fixedRate = 0.997500000000;
double fixedRate1 = 0.1234567890123456789;
System.out.println(String.format("%.19f", fixedRate ));
System.out.println(String.format("%.19f", fixedRate1 ));
Good Luck !
According to your question
for the first the ouput is 0.9975 but late on for next it is not
truncating after decimal points but why for first then
Since double is numeric datatype and hence cannot hold the leading and trailing zeros.
A double doesn't care about formatting - it's about storage only. When you print it, it is converted to a String (using Double's static toString method).
In simple terms the value 0.9975 is not different from 0.997500000000or it is same as 0.997500000000 as zeros after a number will not have any value.
But consider if you had value like this 0.9975000000001 then all the numbers will be printed. Check it here.
If you want to format the value then you can see this question : How to properly display a price up to two decimals (cents) including trailing zeros in Java?

Java Math.pow() Rounding Error

I'm having trouble with (what I suspect is) a rounding error.
I have a string, 0.686357E-01, which I'm trying to convert to a double. I've been able to split it up using the Pattern.split() function, and I'm capturing the base and the exponent values just fine. However, once I try to multiply them appropriately, I get this as a result: 0.06863570000000001.
Here's my relevant code:
pattern = Pattern.compile("E\\+?");
String[] number = pattern.split(string);
double base = Double.parseDouble(number[0]);
int exponent = Integer.parseInt(number[1]);
number= base*Math.pow(10, exponent);
So, how do I avoid the rounding error? (There are ways that I can work around it, but if it's possible to do, then I'd like to know how to fix the issue)
Thanks.
You don't need to split it, Double.parseDouble can handle those kinds of numbers just fine.
double number = Double.parseDouble("0.686357E-01");
See? It works!
0.0686357 is not exactly representable as a double-precision value.
Two solutions:
Use e.g. BigDecimal.
Limit the displayed precision to a certain number of significant figures when converting back to human-readable.
Floating point numbers do not have perfect precision. If that is an issue, use BigDecimal:
String string = "0.686357E-01";
BigDecimal number = new BigDecimal(string);
System.out.println(number);
Double will print always like that, but the value will remain correct. You'll need to format the output to get the correct value. See DecimalFormat class.

How do you trim the BigDecimal division results

BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
double result = numerator.divide(denominator).doubleValue();
Division on certain conditions results in a zero at the end (e.g. 0.0060).
Dividing equal numbers results in a zero at the end (e.g 1.0).
I would prefer to trim the trailing zero in both cases. How should I do this?
How about keeping the result as a BigDecimal and then you can set the scale on it to only represent the significant figures that you want.
An easy way to do this, for some numbers, is to use BigDecimal#stripTrailingZeros(). However, if the number is an integer with trailing zeros you'll get an engineering representation e.g. 600.0 will give you 6E+2. If this isn't what you want, you'll have to detect this condition and manually use BigDecimal#setScale() to set the scale appropriately.
If you need to keep to a restricted maximum number of decimal digits you'll need to use alternative formatting/rounding mechanisms before applying this technique.
It's also a good idea to only do this on values that you're going to display, not on the internal values of your model. Treat it as a view/presentation layer modification.
If you must convert to a double, then it's only the formatted representation you can alter. In this case, if you've got a variable number of decimal places that you want to format to, I'd just drop it into a string/character array, scan backwards for the first non-zero character and truncate it there. Not the most performant means, but simple and reliable.
You could even use a regex for this purpose.
you can do this by using DecimalFormat. something like:
DecimalFormat df = new DecimalFormat(".0");
double formatResult = df.format(result);
will create something of 1.0 if the result is 1.278494890. there are many possible patterns that could be used here
Ok, so you've got this code:
BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
double result = numerator.divide(denominator).doubleValue();
and you want more control over your output. Since result is a double, which is a primitive, you won't have much control.
From my understanding, you don't want to do any rounding to n decimal places, you want original precision paired with desired formatting.
You have few options.
BigDecimal numerator = new BigDecimal(numerator);
BigDecimal denominator = new BigDecimal(denominator);
BigDecimal div = numerator.divide(denominator);
If you stay with BigDecimal, your output will be better. If you put 10 as the numerator and denominator in above code, System.out.println(div) will yield 1.
Generally, be careful of using above code because some combinations of numerator and denominator will throw
java.lang.ArithmeticException: "Non-terminating decimal expansion; no exact representable decimal result."
If you want to avoid such situations, and not worry about precision beyond double's internal representation, use double directly.
System.out.println(2312 / 2.543); //909.1624066063704
System.out.println(1.0 / 1.0); //1.0
System.out.println(1 / 1); //1
When using double numbers, you might get a 0 at the end, such as 0.0060 in your case. If you want to be sure what you're getting, you'll have to convert your result to a String using
String dec = String.valueOf(10.0/10.0); //1.0
and then using
String newDec = dec.endsWith("0") ? dec.substring(0, dec.length() - 1) : dec;
to eradicate that last 0. Of course, if your string ends with .0, you have a choice based on your preferences whether you want to leave that leading . or not.

Categories

Resources