使用具有更多数字的Java Double.toString()样式格式(DecimalFormat不适用于低精度数字)

时间:2011-07-29 05:48:11

标签: java double precision tostring decimalformat

核心问题是我需要记录一系列双打,每个双打都有不同数量的有效数字。数字的变化有很大的数字。一些有0(例如5257),有些有2(例如1308.75),有些一直有7(例如124.1171875)。基本上是小数点后0到7位有效数字之间的所有内容。

标准Double.toString()适用于所有内容,但有7位有效数字。这是一直到6位数字,有效数字都打印没有任何无关紧要的数字。但是对于那些有7位有效数字的人,toString()会将最后一位数字舍入。即。

5257 -> "5257"
1308.75 -> "1308.75"
124.1171875 -> "124.117188"

当然我尝试使用DecimalFormat(“#。#######”),这解决了丢失有效数字的问题,但它为许多低精度双精度打印了无关紧要的数字。即。

1308.75 -> "1308.7499998"

这也是不可接受的,因为它浪费了大量的空间(通常每天记录> 2 GB的数据)和2)它使用日志弄乱了应用程序。

在识别有效数字时,与toString()相比,DecimalFormat看起来很糟糕,无论如何要修复它?我只想使用toString()样式处理有效数字,并将最大位数从6扩展到7。

有什么想法吗? 感谢

3 个答案:

答案 0 :(得分:7)

如果你担心完全保留十进制值,那么你应该使用BigDecimal作为二进制浮点类型,从根本上不适合double。< / p>

碰巧,我无法在DecimalFormat中重现您对1308.75的行为,这并不让我感到惊讶,因为该值 可以完全代表double。事实上,DecimalFormat似乎正在应用一些启发式方法,因为即使1308.76也是1308.76 - 这让我感到惊讶,因为实际值是1308.759999999999990905052982270717620849609375。这确实意味着如果您在代码中使用1308.7599999999999,它将显示为1308.76,因为它与double相关的值完全相同。如果您需要区分这两个值,那么您肯定应该使用BigDecimal

另请注意,1308.75有6个有效数字 - 它有2个小数位。值得注意区分这两个概念。

答案 1 :(得分:3)

在我看来有点奇怪,这就是我出去测试的原因。 我试过这段代码:

public class MySimpleTest
{
    public static void main(String args[])
    {
        format(5257);
        format(1308.75);
        format(124.1171875);
    }

    private static void format(double d)
    {
        DecimalFormat df = new DecimalFormat("##.#######");
        System.out.println("" + d + " -> " + df.format(d));
    }
}

它给了我这个结果:

5257.0 -> 5257
1308.75 -> 1308.75
124.1171875 -> 124.1171875

您可能正在测试“##。######”(点后只有6#),或者您的号码可能有尾随数字。关键是##。#######和##。0000000格式将围绕最后一个小数点(例如,格式化之前124.11718755将四舍五入为124.1171876)。如果你想要它被截断,首先尝试截断它,做这样的事情:

double d = 124.1171875999999;
org.apache.commons.math.util.MathUtils.round(d, 6, java.math.BigDecimal.ROUND_DOWN);
DecimalFormat df = new DecimalFormat("##.#######");
System.out.println("" + d + " -> " + df.format(d));

答案 2 :(得分:-1)

除了Jon Skeet所提到的,为什么不保留一个DecimalFormat数组,每个数组都包含多个数字?