Is there a Java number formatting library that handles significant digits?

心已入冬 提交于 2019-12-03 19:54:28

问题


The built in DecimalFormat only allows you to specify number of digits to the right of the decimal place.

Because of the limitations of representing numbers as double, number formatting needs to include some level of rounding inside of it. In the general case, that rounding has to be to a number of significant digits (default case is the precision of a double) or else your formatted double will end up showing stuff like 3.5999999 instead of 3.6.

The closest solution I could find is using

new BigDecimal(double, new MathContext(14, RoundingMode.HALF_EVEN).stripTrailingZeros().toPlainString()

however, that only provides a single format. If I need to format it generally (group separator, decimal separator, limit to number of digits, padding, etc.), there is nothing in the JDK library.

Is there a general number formatting library out there that will handle rounding to significant digits properly?

Someone asked for examples. So, let's say I wanted to format to 4 significant digits, then:

0.000003599999 -> 0.0000036
4.12345 -> 4.123
1234.345 -> 1234

The general approach we would take would be to round to 14 digits since depending on the circumstances, a double can only represent around 15-17 significant digits anyway (or so I've read).


回答1:


This adds a lot of overhead (5 MB or so), but the International Components for Unicode project has an enhanced DecimalFormat that handles significant digits nicely.

http://icu-project.org/apiref/icu4j/com/ibm/icu/text/DecimalFormat.html#sigdig

DecimalFormat formatter = new DecimalFormat();
formatter.setMaximumSignificantDigits( 4 );
System.out.println( formatter.format( hoursSinceLastAccident ) );



回答2:


What about such solution:

double l = 34563.35129854289;
short offset = (short) Math.ceil(Math.log10(l) + 1);
short significantDigits = 10;

System.out.printf("%,." + (significantDigits - offset) + "f", l);
//String output = String.format("%,." + (significantDigits - offset) + "f", l);

Output:

34 563,3513 (i.e. ',' in printf indicates to use group separator)




回答3:


It's worth mentioning that if it's specifically Android and not Java that's being targeted, the built in DecimalFormat supports formatting for significant figures via the @ symbol.

String smallPi = new DecimalFormat("@@@").format("3.14159"); // formats number as '3.14'



回答4:


I found this nice way of doing it.

This is if you just want to print it out.

public String toSignificantFiguresString(BigDecimal bd, int significantFigures){
    return String.format("%."+significantFigures+"G", bd);
}

This is if you want to convert it:

public BigDecimal toSignificantFigures(BigDecimal bd, int significantFigures){
    String s = String.format("%."+significantFigures+"G", bd);
    BigDecimal result = new BigDecimal(s);
    return result;
}

Here's an example of it in action:

    BigDecimal bd2 = toSignificantFigures(BigDecimal.valueOf(4.12345), 4);
    BigDecimal bd3 = toSignificantFigures(BigDecimal.valueOf(1234.345), 4);
    BigDecimal bd4 = toSignificantFigures(BigDecimal.valueOf(0.000003599999), 4);

    System.out.println("bd2: " + String.format("%f",bd2));
    System.out.println("bd3: " + String.format("%f",bd3));
    System.out.println("bd4: " + String.format("%f",bd4));


来源:https://stackoverflow.com/questions/5474742/is-there-a-java-number-formatting-library-that-handles-significant-digits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!