4

I want to format Java doubles much like String.valueOf(double) does, that is, without loss of precision. But I need to use locale-dependent thousand-separators and would prefer a formatter String, as in String.format. I don't need vertical alignment of several numbers. Examples (in Locale.US):

1.0 -> "1.0"
1.1 -> "1.1"
1.11 -> "1.11"
1000 * Math.PI -> "3,141.592653589793"
1e9 -> "1,000,000,000.0"
1.234567890123e9 -> "1,234,567,890.123"

Any better suggestion than the following hack, involving parsing the result of String.valueOf(d) to calculate the number of decimal places?

double d = ...
String s = String.valueOf(d);
int exponent = s.indexOf('E');
int decimals;
if (0 <= exponent) {
   decimals = Math.max(1, exponent - s.indexOf('.') - Integer.parseInt(s.substring(exponent + 1)) - 1);
}
else {
   decimals = s.length() - s.indexOf('.') - 1;
}
String format = "%,." + decimals + "f";
System.out.printf("Value: " + format + "\n", d);
mravn
  • 151
  • 6
  • DecimalFormat may be a better choice here. – Peter Lawrey Jan 10 '12 at 12:57
  • If precision is a concern, you should be using java.math.BigDecimal for your calculations. double and float can both lose precision. – jt. Jan 10 '12 at 13:00
  • @jt. I'm not concerned with loss of precision in general (not working with money), only about losing precision relative to the double values. – mravn Jan 10 '12 at 13:42
  • 1
    Since you noted in the comments of [`ymene`](http://stackoverflow.com/users/210290/ymene)'s [answer](http://stackoverflow.com/a/8803761/649852) that you would like a valid `String.format` format string, take a look at [this question](http://stackoverflow.com/questions/2301047/how-to-java-string-format-with-a-variable-precision) on `String.format` variable precision. In all likelihood, you're probably not going to get any better than what you already have unless you can remove the `String.format` restriction and use, for example, `NumberFormat`. – Go Dan Jan 10 '12 at 14:23

2 Answers2

2

Check out DecimalFormat: http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html

Jeremiah Orr
  • 2,620
  • 1
  • 18
  • 24
2

Have a look at NumberFormat or DecimalFormat

For Example:

double d = 1.234567890123e9;

//Initiating a format depending on current locale:
final NumberFormat format = NumberFormat.getInstance();
format.setGroupingUsed( true );
System.out.println( format.format( d ) );

prints:

1,234,567,890.123

But when it comes to precision you might should consider using a different datatype like BigDecimal.

crusam
  • 6,140
  • 6
  • 40
  • 68
  • Thanks - I don't need any more precision than that provided by doubles (I'm not working with money). I do need calls to setMin/MaxFractionDigits in addition to setGroupingUsed, but otherwise it behaves as wanted. Except... I can't interoperate with String.format upon which the rest of my code is based :-/ – mravn Jan 10 '12 at 13:31
  • Oh - and NumberFormat behaves differently from String.format on NaN and +/-Infinity. – mravn Jan 10 '12 at 13:33
  • You are free to extend NumberFormat in any way you want, for example DecimalFormat is also an extension of NumberFormat. Feel free to change its behaviour to your concerns. Unfortunatly I do not understand which kind of interoperation with String.format you are talking about. – crusam Jan 10 '12 at 13:43
  • I mean solving the problem by finding a suitable format String. I'm working with an API that takes format Strings as arguments. – mravn Jan 10 '12 at 13:48