views:

387

answers:

7

Hello. I'm trying to get rid of unnecessary symbols after decimal seperator of my double value. I'm doing it this way:

DecimalFormat format = new DecimalFormat("#.#####");
value = Double.valueOf(format.format(41251.50000000012343));

But when I run this code, it throws:

java.lang.NumberFormatException: For input string: "41251,5"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
    at java.lang.Double.valueOf(Double.java:447)
    at ...

As I see, Double.valueOf() works great with strings like "11.1", but it chokes on strings like "11,1". How do I work around this? Is there a more elegant way then something like

Double.valueOf(format.format(41251.50000000012343).replaceAll(",", "."));

Is there a way to override the default decimal separator value of DecimalFormat class? Any other thoughts?

+2  A: 

You can't change the internal representation of double/Double that way.

If you want to change the (human) representation, just keep it String. Thus, leave that Double#valueOf() away and use the String outcome of DecimalFormat#format() in your presentation. If you ever want to do calculations with it, you can always convert back to a real Double using DecimalFormat and Double#valueOf().

By the way, as per your complain I'm trying to get rid of unnecessary symbols after decimal seperator of my double value, are you aware of the internals of floating point numbers? It smells a bit like that you're using unformatted doubles in the presentation layer and that you didn't realize that with the average UI you can just present them using DecimalFormat without the need to convert back to Double.

BalusC
The problem is when I convert it to `String`, it then won't convert back to `Double`, using `Double.valueOf()`, because `DecimalFormat` places `,`, where `valueOf()` is expecting `.`.So is there a way to override this in `DecimalFormat` class (so that I don't have to place a call to `replaceAll(",", ".")` there)?
folone
Use `DecimalFormat` to reformat it into the format as expected by `Double`.
BalusC
Yeah, but `DecimalFormat` places it's default decimal separator (which is `,`). How do I make it place `.` instead?
folone
The separator is locale dependent. Ensure that you get the right `DecimalFormat` instance for the desired locale.
BalusC
@folone See my answer, e.g. `Locale.setDefault(Locale.ENGLISH)`
Tobias Kienzler
Goldberg's paper is *way* too high-level to serve as a basic introduction to floating point to be thrown at newbies in the manner or RTFM. For this reason I've written http://floating-point-gui.de/
Michael Borgwardt
@Michael: now that's a nice one. I updated the link accordingly.
BalusC
I don't actually use doubles in gui or currency presentations (here I use them for Ole Date representation). But thanks, that's a great link.
folone
+1  A: 

Use Locale.getDefault() to get your System's decimal separator which you can also set. You can't have to different separators at the same time since the other is then usually used as seprator for thousands: 2.001.000,23 <=> 2,001,000.23

Tobias Kienzler
+2  A: 

For the ',' instead of the '.' , you'd have to change the locale.

For the number of decimals, use setMaximumFractionDigits(int newValue)

For the rest, see the javadoc

Maxime ARNSTAMM
+4  A: 

The fact that your formatting string uses . as the decimal separator while the exception complains of , points to a Locale issue; i.e. DecimalFormat is using a different Locale to format the number than Double.valueOf expects.

In general, you should construct a NumberFormat based on a specific Locale.

Locale myLocale = ...;
NumberFormat f = NumberFormat.getInstance(myLocale);

From the JavaDocs of DecimalFormat:

To obtain a NumberFormat for a specific locale, including the default locale, call one of NumberFormat's factory methods, such as getInstance(). In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.

However as BalusC points out, attempting to format a double as a String and then parse the String back to the double is a pretty bad code smell. I would suspect that you are dealing with issues where you expect a fixed-precision decimal number (such as a monetary amount) but are running into issues because double is a floating point number, which means that many values (such as 0.1) cannot be expressed precisely as a double/float. If this is the case, the correct way to handle a fixed-precision decimal number is to use a BigDecimal.

matt b
This actually helped:`DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(Locale.getDefault());` `unusualSymbols.setDecimalSeparator('.');``DecimalFormat format = new DecimalFormat("#.#####", unusualSymbols);`
folone
A: 

By

get rid of unnecessary symbols after decimal seperator of my double value

do you actually mean you want to round to e.g. the 2nd decimal? Then just use

value = Math.round(value*1e2)/1e2;
Tobias Kienzler
No, I want to round it to the fifth decimal.
folone
then replace the two `1e2` by `1e5`. Don't use Strings for this, it wastes performance
Tobias Kienzler
+2  A: 

The problem is that your decimal format converts your value to a localized string. I'm guessing that your default decimal separator for your locale is with a ','. This often happens with French locales or other parts of the world.

Basically what you need to do is create your formatted date with the '.' separator so Double.valueOf can read it. As indicated by the comments, you can use the same format to parse the value as well instead of using Double.valueOf.

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));
Chris Dail
or `DecimalFormat format = new DecimalFormat("#"+symbols.getDecimalSeparator+"#####", symbols;` without changing the decimal separator
Tobias Kienzler
Yeah, that worked just fine.
folone
If you already have the DecimalFormat, why not use it for parsing as well? Much more robust than trying to build a DecimalFormat whose formatted output can be parsed by Double.valueOf()
Michael Borgwardt
@Michael Borgwardt Good point. I've updated the answer to include that
Chris Dail
A: 

Somewhat related to this, but not an answer to the question: try switching to BigDecimal instead of doubles and floats. I was having a lot of issue with comparisons on those types and now I'm good to go with BigDecimal.

Joao