aspose file tools*
The moose likes Java in General and the fly likes Big Problem with decimalFormat Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Big Problem with decimalFormat" Watch "Big Problem with decimalFormat" New topic
Author

Big Problem with decimalFormat

Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Hi,
My first post, and its a good one ...
We are about to go to IST with a rather large reporting application developed in JSP against an Oracle database.
We are using a home grown JDBC based database pooling class.
We are using the decimalFormat class to format the output into whole numbers with commas separating the thousands.
We are using jdk1.2.2 on Solaris 8
The problem I have is that the decimalFormat.format method appears to randomly return incorrect values.
I am using the declaration fmt = new decimalFormat("#,##0")
and then simply calling fmt.format(number as a string)
For instance, on one particular report, the there are two values returned from the database, both are '0'
The first number is formatted to 0, but the second is formatted to 1.
If I change the format declaration to "#,##0.0" then I get 0.0
for both numbers.
Even weirder is that if I call the fmt.format() twice on the second variable, then I get return 1 and then 0
Any suggestions ?
Thanks,
Andrew.
Sean MacLean
author
Ranch Hand

Joined: Nov 07, 2000
Posts: 621
It sounds like the BigDecimal is doing some rounding on you. What is the nature of the data being put into the DB (and then retrieved)? Could you round your data to an int value before putting it into the DB so that you can control it? Have you tried extracting the date as a float and examining the difference straight from the DB. What is the number field length in the DB? Perhaps there is some sort of cropping going on there. These are some of the things that jump to mind and may reveal the source of the issue. You could also write your own parser and avoid the using a BigDecimal object all together.
Sean
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Sean,
Thanks for the reply.
I am not using BigDecimal at all.
I am retrieving the numbers directly from the database into a string and then using decimalFormat to apply a format to the string.
I have to convert the String to a Double before passing it to DecimalFormat.format, as it only accepts Doubles or Longs as an argument.
For instance.
{
DecimalFormat fmt = new DecimalFormat("#,##0");
ResultSet rs = stmt.executeQuery("select number from table"):
while(rs.next())
{
String num = rs.getString(1);
System.out.println(fmt.format(new Double(num)));
}
}
If the table contains two rows, both of which contain a single numeric column with a value of exactly 0, then the program will return ...
0
1
If I change the first line to
decimalFormat fmt = new decimalFormat("#,##0.0");
the it will return
0.0
0.0

Looks like I might have to write my own formatting class, as there doesn't appear to be any other way to do this.
Andrew.

[This message has been edited by Andrew Wilcockson (edited August 02, 2001).]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Something's wrong here:
<code><pre>
String num = rs.getString(1);
System.out.println(fmt.format(num));
</pre></code>
There is no format method in DecimalFormat which will format a String. You should probably recheck your code to see what you're really doing.
The rest of this reply was written before I noticed that inconsistency; it may still be useful.
If you're sure that the two input strings are identically zero (why not print the string value to be sure?), then it looks like a bug. I found a few bug reports for DecimalFormat in 1.2.2 and earlier, but none sounded very similar to this. Nonetheless, I'd recommend upgrading to 1.3.0 or 1.3.1, which have been out for a while. Chances are good the problem will mysteriously get better. Another possibility worth trying is to set the properties of the DecimalFormat using methods rather than an initialization string:
<code><pre>
DecimalFormat df = new DecimalFormat();
df.setMinimumIntegerDigits(1);
df.setMaximumIntegerDigits(4);
df.setMaximumFractionalDigits(0);
df.setDecimalSeparatorAlwaysShown(false);
df.setGroupingSize(3);
</pre></code>
This will probably give the same results as the original code - but if the bug is in the interpretation of the initialization string, rather than elsewhere, you may bypass it. Good luck...


"I'm not back." - Bill Harding, Twister
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Hi Jim,
Thanks for the suggestions, I will give it a try.
I actually had the code doing the following ...
while(rs.next())
{
String num = rs.getString(1);
System.out.println(fmt.format(new Double(num)));
System.out.println(fmt.format(new Double(num)));
}
and was getting ...
0 <- result from first row
0
1 <- result from second row
0
Note that the code has now been modified. This is the downside of a frazzled developer trying to chop out the important pieces of code to stick in a post, when the stupid netscape browser that he is forced to use does not allow cut & past
Also, this code is actually in jsps (ie no System.out.println), and I have simply produced some super-pseudo code to help people understand the problem.
Forgot to mention that we are forced to use 1.2.2 as it is the 'standard'. I won't mention where I am working, but lets just say it starts with S, end win N and there's only one letter in between
I'll let you know how I get on.
Andrew.

[This message has been edited by Andrew Wilcockson (edited August 02, 2001).]
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Nice try Jim,
but unfortunately exactly the same results.
interestingly, if I use
df.setMaximumFractionalDigits(1);
then the zeros stay as 0, but the rows with fractional parts display the first decimal place.
Thanks anyway.
Anyone else got another suggestion
Thanks,
Andrew.
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Still, just as an experiment it might be nice to see if going to 1.3 or even 1.4 beta fixes the problem. If not, then there's a good chance your problem is actually elsewhere - I imagine a bug in DecimalFormat would have been fixed by now.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Put the line
System.out.println(num);
into the loop. Hopefully this will cast some light on the problem...


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Ilja,
Been there, done that
This is the infuriating thing.
If I change the code to ...
while(rs.next())
{
String num = rs.getString(1);
System.out.println(num);
System.out.println(fmt.format(new Double(num)));
System.out.println(fmt.format(new Double(num)));
}
I get ...
0 <- result from first row
0
0
0 <- result from second row
1
0
It just don't add up
Andrew.
Sean MacLean
author
Ranch Hand

Joined: Nov 07, 2000
Posts: 621
Sorry, I don't know what got me thinking you were using the BigDecimal class. Does the data have to be store in the DB as a String?
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Next try:
use fmt.format(Double.parseDouble(num));
or, even simpler, try:
double num = rs.getDouble(1);
According to suns jdbc tutorial, this should even work on character-rows.
[This message has been edited by Ilja Preuss (edited August 03, 2001).]
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Hi Guys,
I think we are all getting a bit confused
The data is stored in an Oracle database as numeric(10,2) data.
I am using rs.getString and then creating a new Double from the String as this seems more stable (ie less likely to cause unpredictable Exceptions) than using rs.getDouble.
Although I can't seem to replicate the problem in a simple, non database test problem, I am fairly convinced that the problem is in the DecimalFormat class.
Unfortunately we have no IDE so I cannot set breakpoints and trace into the code to see what is happening withing the DecimalFormat.format method.
I am convinced of the problem though by the following bit of pseudo-code
DecimalFormat fmt = new DecimalFormat("#,##0");
while(rs.next())
{
String num = rs.getString(1);
System.out.println(num);
System.out.println(fmt.format(new Double(num)));
System.out.println(fmt.format(new Double(num)));
}
which produces the output ...
0 <- result from first row
0
0
0 <- result from second row
1
0
If I change line 1 to
DecimalFormat fmt = new DecimalFormat("#,##0.0");
I get ...
0.0 <- result from first row
0.0
0.0
0.0 <- result from second row
0.0
0.0
Which tells me that there is a systematically random error in DecimalFormat.format
Thanks for all the help,
Andrew.

[This message has been edited by Andrew Wilcockson (edited August 03, 2001).]
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
I assume the second DecimalFormat was created with "#,##0.0", not "#,##0".
Try creating the DecimalFormat inside the while loop, so you get a new one for each row. Obviously this is less efficient than what you have, but it may be enough to work around whatever bug may be in DecimalFormat.
Andrew Wilcockson
Greenhorn

Joined: Aug 02, 2001
Posts: 10
Jim,
Oops, yes you are correct, I've modified the post.
I will give this a try on Monday, and let you know how it goes.
Thanks for the suggestion,
Andrew.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Why won't you try
fmt.format(Double.parseDouble(num));
???
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Big Problem with decimalFormat