2

I am unable to define DecimalFormat instance (in Java1.8) with the following properties:

  • Scientific notation (exponent) is used only if the exponent is negative.
  • At most 4 significant places are shown, i.e., no 0s at the end.

(I can live without the second property being satisfied if necessary.)

The purpose is to convert doubles to strings, i.e., to use the format method. Here is the desired behaviour on some examples:

Representation of 9: 9
Representation of 9.0: 9
Representation of 9876.6: 9877
Representation of 0.0098766: 9.877E-3
Representation of 0.0000000098766: 9.877E-9

If I define DecimalFormat df = new DecimalFormat("#.###E0");, this gives

Representation of 9: 9E0
Representation of 9.0: 9E0
Representation of 9876.6: 9.877E3
Representation of 0.0098766: 9.877E-3
Representation of 0.0000000098766: 9.877E-9

which is wrong in the first three cases. Things like DecimalFormat("#.###E#") or DecimalFormat("#.###E") are not allowed (IllegalArgumentException is thrown).


The code that produced the output is given below.

DecimalFormat df = new DecimalFormat("#.###E0");
double[] xs = new double[] {9, 9.0, 9876.6, 0.0098766, 0.0000000098766};
String[] xsStr = new String[] {"9", "9.0", "9876.6", "0.0098766", "0.0000000098766"};
for(int i = 0; i < xs.length; i++) {
    System.out.println("Representation of " + xsStr[i] + ": " + df.format(xs[i]));
}
Antoine
  • 862
  • 7
  • 22
  • 1
    Couldn't you use two formatters? Format with what you have already, use a regex to check that the decimal is negative, and if it is not then format with a different one that doesn't use scientific notation. – Diasiare Apr 05 '18 at 14:45
  • @Diasiare The problem is that the current formatter is used all over the code. By far the best option is to simply redefine it ... The second best option is to define the second formatter that is used in the cases when things are known to be "big". However, that would take some time ... – Antoine Apr 05 '18 at 14:49

2 Answers2

2

You can try an if statement to check if the number is below 1.

if (xs < 1) {
    System.out.println("Representation of " + xsStr[i] + ": " + df.format(xs[i]));
}
else {
    System.out.println("Representation of " + xsStr[i] + ": " + xs[i];
}

Another option would be to use a ternary operator.

System.out.println("Representation of " + xsStr[i] + ": " + xs[i] < 1 ? df.format(xs[i]) : xs[i]);

This answer does a good job at explaining how it works. https://stackoverflow.com/a/25164343/

tristan
  • 98
  • 8
0

I don't think you can achieve your goal using the normal DecimalFormatter class. If everything uses the same instance of DecimalFormatter then you might be able to subclass DecimalFormatter and then apply something like tristan's answer inside the overwritten format method.

If you do this make sure that the parse method isn't used anywhere, or if it is make sure to override that too.

Diasiare
  • 745
  • 1
  • 6
  • 18
  • Oh, that is actually good enough. This subclass could than have two usual `DecimalFormatter` fields and the overwritten `format` would simply choose the appropriate one and call the standard format on it. – Antoine Apr 05 '18 at 15:15
  • Actually, extending `DecimalFormat` is not necessary ... This will also prevent possible issues of using `parse` method. – Antoine Apr 06 '18 at 09:25