简体   繁体   English

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

[英]Using Java Double.toString() style formatting with more digits (DecimalFormat does not work with low precision numbers)

The central problem is that I have a series of doubles that I need to log, each with varying number of significant digits. 核心问题是我需要记录一系列双打,每个双打都有不同数量的有效数字。 The numbers vary greatly in how many significant digits they have. 数字的变化有很大的数字。 Some have 0 (eg 5257), some have 2 (eg 1308.75), some have all the way up to 7 (eg 124.1171875). 一些有0(例如5257),有些有2(例如1308.75),有些一直有7(例如124.1171875)。 Basically everything between 0 to 7 significant digits after the decimal. 基本上是小数点后0到7位有效数字之间的所有内容。

Standard Double.toString() works excellent on everything BUT those with 7 significant digits. 标准Double.toString()适用于所有内容,但有7位有效数字。 That is all the way up to 6 digits, the significant digits are all printed without any insignificant digits. 这是一直到6位数字,有效数字都打印没有任何无关紧要的数字。 But on those with 7 significant digits, toString() rounds off the last digit. 但是对于那些有7位有效数字的人,toString()会将最后一位数字舍入。 Ie

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

Of course I tried using DecimalFormat("#.#######"), and that resolved the problem of missing significant digits, but it printed insignificant digits for many of the low precision doubles. 当然我尝试使用DecimalFormat(“#。#######”),这解决了丢失有效数字的问题,但它为许多低精度双精度打印了无关紧要的数字。 Ie

1308.75 -> "1308.7499998"

This is also unacceptable as 1) it wastes a significant amount of space (typically log >2 GB of data a day) and 2) it messes up the applications using the logs. 这也是不可接受的,因为它浪费了大量的空间(通常每天记录> 2 GB的数据)和2)它使用日志弄乱了应用程序。

DecimalFormat seems to suck compared to toString() when it comes to identifying significant digits, is there anyway to fix it? 在识别有效数字时,与toString()相比,DecimalFormat似乎很糟糕,无论如何要修复它? I just want to use toString() style handling of significant digits, and extend the maximum number of digits from 6 to 7. 我只想使用toString()样式处理有效数字,并将最大位数从6扩展到7。

Any ideas? 有任何想法吗? Thanks 谢谢

If you're concerned about preserving decimal values exactly, you should use BigDecimal to start with - double is fundamentally inappropriate, as a binary floating point type. 如果你担心完全保留十进制值,你应该使用BigDecimal开始 - double从根本上说是不合适的,作为二进制浮点类型。

As it happens, I can't reproduce your behaviour of 1308.75 in DecimalFormat , which doesn't surprise me because that value is exactly representable as a double . 碰巧的是,我无法在DecimalFormat重现你1308.75的行为,这并不让我感到惊讶,因为这个值可以完全表示为double In fact, DecimalFormat appears to be applying some heuristics anyway, as even 1308.76 comes out as 1308.76 - which surprises me as the actual value is 1308.759999999999990905052982270717620849609375. 事实上,无论如何, DecimalFormat似乎应用了一些启发式算法,因为即使1308.76也是1308.76 - 这让我感到惊讶, 实际值是1308.759999999999990905052982270717620849609375。 It does mean that if you use 1308.7599999999999 in your code, it will come out as 1308.76, because it's the exact same value as far as double is concerned. 它意味着,如果你在代码中使用1308.7599999999999,它会出来为1308.76,因为它是完全一样的价值尽可能double关注。 If you need to distinguish between those two values, you should definitely be using BigDecimal . 如果你需要区分这两个值,你肯定应该使用BigDecimal

Also note that 1308.75 has 6 significant digits - it has 2 decimal places . 另请注意,1308.75有6 位有效数字 - 它有2 位小数 It's worth being careful to differentiate between the two concepts. 值得注意区分这两个概念。

It seemed to me a bit strange, that's why I went out and tested. 在我看来有点奇怪,这就是我出去测试的原因。 I tried this code: 我试过这段代码:

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

And it gave me this result: 它给了我这个结果:

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

You probably were testing with "##.######" (only 6 #s after dot), or your number might have had trailing digits. 您可能正在测试“##。######”(点后只有6#),或者您的号码可能有尾随数字。 The point is that ##.####### and ##.0000000 formats will round the last decimal point (eg 124.11718755 will be rounded to 124.1171876 before formatting). 重点是##。#######和##。0000000格式将围绕最后一个小数点(例如,格式化之前124.11718755将四舍五入为124.1171876)。 If you want it to be truncated try to truncate it first, doing something like this: 如果你想要它被截断,首先尝试截断它,做这样的事情:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java DecimalFormat在格式化double时丢失精度 - Java DecimalFormat losing precision while formatting double Double.toString(2.0)在Java中不是“ 2.0”吗? - Double.toString(2.0) is not “2.0” in Java? 使用 DecimalFormat 格式化数字 - Formatting numbers using DecimalFormat 在Java中将double转换为char数组的算法(不使用Double.toString或StringBuilder之类的对象)? - Algorithm to convert a double to a char array in Java (without using objects like Double.toString or StringBuilder)? 如果分数不能用二进制精确表示,Double.toString()如何工作? - How does Double.toString() work if a fraction number cannot be precisely represented in binary? Java7 Double.toString()返回0.005 / java6,它是0.0050 - Java7 Double.toString() returns 0.005 / java6 it is 0.0050 Double.toString,两位小数 - Double.toString with two decimals String.format选项可用于特定于语言环境的双重格式,例如Double.toString()? - String.format option for locale specific double formatting like Double.toString()? Java将小数格式化为2位精度 - Java formatting decimals to 2 digits precision 使用DecimalFormat将双精度格式格式化为String会引发IllegalArgumentException - Formatting a double to String using DecimalFormat is throwing IllegalArgumentException
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM