是否有一个Java数字格式库来处理重要的数字?

时间:2021-04-13 11:48:39

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

内建的DecimalFormat只允许您指定小数点右边的位数。

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.

由于数字表示为double的限制,数字格式需要包含一定程度的舍入。在一般情况下,四舍五入必须是若干位有效数字(默认情况下是双精度),否则格式化后的双精度将显示3.599999999而不是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.

然而,这只提供了一种格式。如果我需要格式化它(组分隔符、十进制分隔符、限制数字、填充等),那么JDK库中就没有任何内容了。

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:

有人问为例子。假设我想要格式化4位有效数字,然后:

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).

我们通常采用的方法是四舍五入到14位数,因为根据具体情况,双位数只能代表大约15-17位有效数字(至少我读过)。

4 个解决方案

#1


9  

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.

这增加了很多开销(5 MB左右),但是Unicode项目的国际组件有一个改进的小数格式,可以很好地处理重要的数字。

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

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


2  

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.

值得一提的是,如果目标是Android而不是Java,那么内置的DecimalFormat支持通过@符号对重要人物进行格式化。

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

#3


1  

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)

34 563、3513(即。','在printf中指示使用组分隔符)

#4


-1  

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));

#1


9  

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.

这增加了很多开销(5 MB左右),但是Unicode项目的国际组件有一个改进的小数格式,可以很好地处理重要的数字。

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

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


2  

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.

值得一提的是,如果目标是Android而不是Java,那么内置的DecimalFormat支持通过@符号对重要人物进行格式化。

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

#3


1  

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)

34 563、3513(即。','在printf中指示使用组分隔符)

#4


-1  

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));