BigDecimal() omitting leading zero - java

How I can store the BigDecimal() same as input?
I need to store real numbers using BigDecimal() which may contain following:
02.34
0.12
.12
0
000.000
I used the following approach :
Scanner sc= new Scanner(System.in);
int n=sc.nextInt();
BigDecimal[] amount = new BigDecimal[n];
for(int i=0;i<n;i++) {
amount[i]=sc.nextBigDecimal();
}
But while printing, it prints formatted. Like this:
2.34
0.12
0.12
0.000
0
I want it should be same as inputted. Therefore please let me know that how could I manage to store inputs intact.

the following code should solve your problem, Keep your string as is and convert it into BigDecimal only when you are comparing
Arrays.sort(s, Collections.reverseOrder(new Comparator<String>() {
#Override
public int compare(String a1, String a2) {
BigDecimal a = new BigDecimal(a1);
BigDecimal b = new BigDecimal(a2);
return a.compareTo(b);
}
}));

Since input is originally a string, the only way to store it intact is to store it as a String.
If you later need to do some math on the numbers, convert them then. You could also possibly store them as both String and BigDecimal in an object.

If you want to store input intact, store it as a String. This is exactly the built-in type dedicated to storing character sequences exactly as entered.
BigDecimal, on the other hand, has a numeric representation with no mechanism for storing its decimal input. In fact, you can initialize BigDecimal without providing a decimal representation at all - e.g. through a sequence of arithmetical operations, in which case the initial representation would not be applicable at all.
If you need to do this in many places, make a class for it. Store the original string, along wit BigDecimal that it represents. This way you would be able to do the conversion only once, and keep the original representation along with it:
class OrigBigDecimal {
private String orig;
private BigDecimal val;
public OrigBigDecimal(String s) {
orig = s;
val = new BigDecimal(s);
}
public String toString() { return s; }
public BigDecimal getVal() { return val; }
}

There are a number of ways to approach this:
1- You can create a small elegant object that has 2 variables, a BigDecimal and a string, and its constructor takes the input as a string, store it in a string and parse it and store it in the BigDecimal.
2- You can configure the BigDecimal output format per input:
Format of BigDecimal number
Format a BigDecimal as String with max 2 decimal digits, removing 0 on decimal part

Related

How to change decimal value string into int without loosing decimal values?

I am working on a pretty old Java application and I can not change Integer field to something else which can hold decimal values, so I need to convert some decimal string like "100.00", "3.33" "33.44" to Integer without loosing fractional values.
#Test
public void NumberFormatTest(){
String stringValue = "100.00";
int testTest = ? //what I can do here to get exact 100.00 in testTest variable ?
log.info("outPutValue {} ", testTest);
}
Currently its using Integer.parseInt(stringValue) and this is throwing
java.lang.NumberFormatException: For input string: "100.00"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
I am working on pretty old java code application and I can not change Integer field to something else which can hold decimal values
That is because int can only hold whole numbers. For decimal values you need to use float or double:
String s = "3.33";
double d = Double.parseDouble(s);
Alternatively, you might want to look into BigDecimal. Depending on your exact needs, this might be a better fit.
p.s. int, float and double are primitive types. Integer, Float and Double are class wrapper for those types. These are two different things. I recommend you read more about these differences to gain a better understanding.

Is there a way to assign a formatted BigDecimal number to a BigDecimal?

I have a piece of code which has two BigDecimal variables. Both the variables are sent to the method format(which works fine) and then printed. The variable "d" is sent to the format method and then printed directly without assigning it(since the method format returns a string).
The problem occurs in the variable a, where I assign the formatted value(which is a String), convert to a bigDecimal and then store in variable a. The format is kept when I print the value of a, but the format is not there when I print the variable d. How can I assign the formatted value without losing its format to a BigDecimal variable?
public static void main(String[] args) {
BigDecimal d = new BigDecimal("0.0005");
BigDecimal a = new BigDecimal(format(d, 2));
System.out.println(a); // 0.000500
System.out.println(format(new BigDecimal("0.00001"), 3)); // 1.000E-5
}
private static String format(BigDecimal x, int scale) {
NumberFormat formatter = new DecimalFormat("0.0E0");
formatter.setRoundingMode(RoundingMode.HALF_UP);
formatter.setMinimumFractionDigits(scale);
return formatter.format(x);
}
Numbers (no matter what kind of - BigDecima, Float,Long) are to store values (most accurate ones) not their String representation. You cannot "store formatted value" as number and expect it to be represented that way all the time. Everytime you want to have formatted value, you have to format it.
so here
BigDecimal a = new BigDecimal(format(d, 2));
you are just creating new BigDecimal using some formatted number which is a string. That string is parsed back to the number and thats it.
What you expect to happen is similar to saying that you want "string" to be stored "as is" in binary system - as this is how numbers are stored physically. Nope, it will still be bunch of ones and zeroes.

Why am I losing Bigdecimal precision?

I am converting numbers like 5.326.236,56 (money), from a txt and first removing dots and commas, but im losing the decimals, and I already defined the columns as:
#Column(name = "total", precision = 16, scale = 2)
private BigDecimal total;
but I am losing the last 2 digits that correspond to Decimal part
Here is my code:
private BigDecimal parseBigLong(String stringNumber) {
String cvalue = "";
for (int n = 0; n < stringNumber.length(); n++) {
char c = stringNumber.charAt(n);
if (!(".").equals(String.valueOf(c))) {
if (!(",").equals(String.valueOf(c))) {
if (!("-").equals(String.valueOf(c))) {
cvalue = cvalue + c;
}
}
}
}
BigDecimal bigDecimal = ( BigDecimal.valueOf(Long.parseLong(cvalue) / 100));
return bigDecimal;
}
Basically, you are doing an integer division on the long before constructing the BigDecimal.
Naturally, the integer division is producing another long ... which cannot represent those two digits after the decimal point.
You can avoid this by doing the division using BigDecimal:
BigDecimal bigDecimal = BigDecimal.valueOf(Long.parseLong(cvalue))
.divide(new BigDecimal(100));
Or if you don't need to enforce the constraint that cvalue is a valid integer (long) representation:
BigDecimal bigDecimal = (new BigDecimal(cvalue))
.divide(new BigDecimal(100));
There may be a better way. The DecimalFormat class understands all sorts of (localized) number formats. If you create a suitable format and then call setParseBigDecimal(true) the format's parse method will produce a BigDecimal ... directly ... without any string bashing to get rid of comma and period characters. (And you won't need to assume that the input number has exactly two digits after the decimal.)
First, your conversion logic is strange:
You are ripping off all -, , and . from your String, and assume it to be 2 decimals when constructing the BigDecimal.
Which means, if you are given a string 1234.5678, you are going to build 123456.78 as the result.
Depending on what's your intention, here are the answers:
If you want to convert to BigDecimal based on the value in input string
Which means, if you want String "1,234.5678" to become 1234.5678 in BigDecimal, you could make use of DecimalFormat, as described in this question: https://stackoverflow.com/a/18231943/395202
If the strange logic is what you intended to do
Which means, if you want String "1,234.5678" to become 123456.78 in BigDecimal, the specific problem in your code is you are doing a long division, and use the result to construct BigDecimal.
In Java (and many other language), division of integer with integer is going to give you integer as result, so 123456 / 100 is going to give you 1234.
What you want to achieve could be done by
BigDecimal result = BigDecimal.valueOf(longValue).divide(BigDecimal.valueOf(100));
Going back to your code, there are a lot of other problems:
Your string concatenation logic is highly inefficient. You could use StringBuilder (or other way I am suggesting soon)
You do not need to convert a char to a String to do comparison. So you
if (!(".").equals(String.valueOf(c))) {
should be written
if (c != '.') {
You could simply use regex to cleanse your input string:
String cvalue = stringNumber.replaceAll("[.,-]", "");

Bigdecimal Not giving exact output in Java

Im adding three big decimals here, but it should give me accurate answer. I'm having two strings here and then converting to big decimal. Please dont ask why Im using strings. There is some business where I will get these values as string then I need to convert. Please find the code
BigDecimal a= new BigDecimal(100.05); --> This value I receive from web service. Its a decimal value from the service.
String b= "100.05";
String c= "200.03";
System.out.println(a.add(new BigDecimal(b).add(new BigDecimal(c))));
Output it gives
400.1299999999999971578290569595992565155029296875
Where as it should be 400.13
The problem is your use of new BigDecimal(100.05). The value of a is then 100.0499999999999971578290569595992565155029296875.
If you had specified that value as a string instead, all would be well:
BigDecimal a = new BigDecimal("100.05");
String b = "100.05";
String c = "200.03";
System.out.println(a.add(new BigDecimal(b).add(new BigDecimal(c))));
// Output: 400.13
If you only have the input as a double, you can use BigDecimal.valueOf(double) instead of calling the constructor:
BigDecimal a = BigDecimal.valueOf(100.05); // a is now exactly 100.05
Compare the BigDecimal(double) documentation:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. (...)
With that of BigDecimal.valueOf(Double):
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).
new BigDecimal(100.05)
This gives 100.0499999999999971578290569595992565155029296875, because 100.05 cannot be represented exactly as a double.
You have to use string here as well:
new BigDecimal("100.05")
As you get this value from a web-service, you probably convert it from a String to a float/double. If this is the case, just skip that conversion step.
If your web-service stub maps the return value to float/double, you can consider mapping it to a String directly and then feed it to BigDecimal constructor, like this:
double v = 100.05; // Value from web service
BigDecimal a= new BigDecimal(String.valueOf(v));
String b= "100.05";
String c= "200.03";
System.out.println(a.add(new BigDecimal(b).add(new BigDecimal(c))));
Live Example
That works because the string will only contain as many digits as are needed to differentiate the almost-100.05 value from the next value on either side that can be represented, and so we get the string "100.05", which then BigDecimal can process correctly.
You can format the answer to Decimal places using String.format and specifiying how many digits.
System.out.println(String.format("%.2f", a.add(new BigDecimal(b).add(new BigDecimal(c)))));

How can I format a String number to have commas and round?

What is the best way to format the following number that is given to me as a String?
String number = "1000500000.574" //assume my value will always be a String
I want this to be a String with the value: 1,000,500,000.57
How can I format it as such?
You might want to look at the DecimalFormat class; it supports different locales (eg: in some countries that would get formatted as 1.000.500.000,57 instead).
You also need to convert that string into a number, this can be done with:
double amount = Double.parseDouble(number);
Code sample:
String number = "1000500000.574";
double amount = Double.parseDouble(number);
DecimalFormat formatter = new DecimalFormat("#,###.00");
System.out.println(formatter.format(amount));
This can also be accomplished using String.format(), which may be easier and/or more flexible if you are formatting multiple numbers in one string.
String number = "1000500000.574";
Double numParsed = Double.parseDouble(number);
System.out.println(String.format("The input number is: %,.2f", numParsed));
// Or
String numString = String.format("%,.2f", numParsed);
For the format string "%,.2f" - "," means separate digit groups with commas, and ".2" means round to two places after the decimal.
For reference on other formatting options, see https://docs.oracle.com/javase/tutorial/java/data/numberformat.html
Given this is the number one Google result for format number commas java, here's an answer that works for people who are working with whole numbers and don't care about decimals.
String.format("%,d", 2000000)
outputs:
2,000,000
Once you've converted your String to a number, you can use
// format the number for the default locale
NumberFormat.getInstance().format(num)
or
// format the number for a particular locale
NumberFormat.getInstance(locale).format(num)
I've created my own formatting utility. Which is extremely fast at processing the formatting along with giving you many features :)
It supports:
Comma Formatting E.g. 1234567 becomes 1,234,567.
Prefixing with "Thousand(K),Million(M),Billion(B),Trillion(T)".
Precision of 0 through 15.
Precision re-sizing (Means if you want 6 digit precision, but only have 3 available digits it forces it to 3).
Prefix lowering (Means if the prefix you choose is too large it lowers it to a more suitable prefix).
The code can be found here. You call it like this:
public static void main(String[])
{
int settings = ValueFormat.COMMAS | ValueFormat.PRECISION(2) | ValueFormat.MILLIONS;
String formatted = ValueFormat.format(1234567, settings);
}
I should also point out this doesn't handle decimal support, but is very useful for integer values. The above example would show "1.23M" as the output. I could probably add decimal support maybe, but didn't see too much use for it since then I might as well merge this into a BigInteger type of class that handles compressed char[] arrays for math computations.
you can also use the below solution
public static String getRoundOffValue(double value){
DecimalFormat df = new DecimalFormat("##,##,##,##,##,##,##0.00");
return df.format(value);
}
public void convert(int s)
{
System.out.println(NumberFormat.getNumberInstance(Locale.US).format(s));
}
public static void main(String args[])
{
LocalEx n=new LocalEx();
n.convert(10000);
}
You can do the entire conversion in one line, using the following code:
String number = "1000500000.574";
String convertedString = new DecimalFormat("#,###.##").format(Double.parseDouble(number));
The last two # signs in the DecimalFormat constructor can also be 0s. Either way works.
Here is the simplest way to get there:
String number = "10987655.876";
double result = Double.parseDouble(number);
System.out.println(String.format("%,.2f",result));
output:
10,987,655.88
The first answer works very well, but for ZERO / 0 it will format as .00
Hence the format #,##0.00 is working well for me.
Always test different numbers such as 0 / 100 / 2334.30 and negative numbers before deploying to production system.
According to chartGPT
Using DecimalFormat:
DecimalFormat df = new DecimalFormat("#,###.00");
String formattedNumber = df.format(yourNumber);
Using NumberFormat:
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setGroupingUsed(true);
String formattedNumber = nf.format(yourNumber);
Using String.format():
String formattedNumber = String.format("%,.2f", yourNumber);
Note: In all the above examples, "yourNumber" is the double value that you want to format with a comma. The ".2f" in the format string indicates that the decimal places should be rounded to 2 decimal places. You can adjust this value as needed.

Categories