使用DecimalFormat将Double格式化为不使用科学计数法打印

7
我一直在从传感器读数中读取时间戳值,但由于它们以纳秒为单位提供,所以我想将它们转换为双精度并进行转换。结果是一个17位数字加上分隔符。
尝试直接打印会导致科学计数法,这不是我想要的,因此我使用DecimalFormat类将其输出为预期的4位小数。问题是,即使调试器显示了17个十进制数字,甚至在'doubleValue()'调用之后,输出字符串也显示了15个数字。
代码:
...
Double timestamp = (new Date().getTime()) +       // Example: 1.3552299670232847E12
            ((event.timestamp - System.nanoTime()) / 1000000D);
DecimalFormat dfmt = new DecimalFormat("#.####");

switch(event.sensor.getType()){
    case Sensor.TYPE_LINEAR_ACCELERATION:
    case Sensor.TYPE_ACCELEROMETER:
        accel = event.values.clone();
        String line = "A" + LOGSEPARATOR +              
            dfmt.format(timestamp.doubleValue()) + // Prints: 1355229967023.28
...

我认为这可能是一个安卓精度问题,但调试器的格式化程序也显示了错误的精度。我已经在本地的Java程序中测试过,两个调用都具有相同数量的数字。
这是DecimalFormat的错误/限制吗?还是我做错了什么?

1
你的问题是数字不符合格式。尝试使用“##############.####”格式。 - Hot Licks
我也试过那个,但还是检查了一下以防我忘记了。格式“####################.####”(多7位数字)得到的结果相同。 - ravemir
你使用的是 java.util 版本的 DecimalFormat 还是 Android 版本的? - Hot Licks
我认为Android没有DecimalFormat类,因为文档上唯一的一个是来自Java的。文档链接 - ravemir
只是想问一下——Android有自己版本的几个类,这可能会造成混淆。 - Hot Licks
显示剩余5条评论
3个回答

2

在Java中,double类型的尾数只有52位(包括隐藏的1位,实际上是53位)。这相当于15-16个十进制位数(53*log10(2))。超过这个位数的每一位都有点随机,因此转换函数在输出15位小数后就应该停止。

既然您不需要double提供的大数范围,为什么不将值保留为long类型呢?这将给您63个有效位(64位中减去1位表示符号的位)。


这是我的推理:我需要将由两个长整型计算出的纳秒转换为毫秒。但我没有考虑到另一种情况:将毫秒转换为纳秒,这不需要浮点数据。这样我可以保持长整型的精度,只需要在打印输出时将逗号向左移动6位即可。让我测试一下,然后再回复你。 - ravemir
成功了!我不仅得到了另外两个位置,还额外得到了2个。奇怪的是,我本来以为用之前的方法计算出来的最后两个字符只是随机数,但它们与我新计算的长整型数值中的那些数字匹配。 - ravemir
我会授予你奖励,并添加我的自己的格式化答案。不过,我感觉有点傻,因为我曾经考虑过类似的做法,但没有费心或者认为它有问题。 - ravemir
我现在无法颁发悬赏,但如果我忘记了,请随时提醒我。;) - ravemir
差点忘了给你奖励。享受你的声望吧! - ravemir

1

我正在使用String.format进行一些研究,结果也是相同的。

Double timestamp = 1.3552299670232847E12;
System.out.println("it was " + timestamp);
System.out.println("and now " + String.format("%.4f", timestamp));

这是输出结果:

12-12 15:48:58.255: I/System.out(2989): it was 1.3552299670232847E12
12-12 15:48:58.255: I/System.out(2989): and now 1355229967023,2800

也许你是对的,这可能是一个Android精度问题,如果你在Java中尝试它,输出是正确的:http://ideone.com/PBOiet

我会继续搜索...


1

Java的DecimalFormat类和Android的DecimalFormat类确实存在差异,尽管它们使用完全相同的参数,但输出结果不同。

这足以让我尝试Henry的方法,现在我已经尝试过了,我发现我获得了额外的2位精度。我也有信心这些值是准确计算的,因为只涉及到求和和乘法。

这是我最终使用的修改后的代码:

...
long javaTime = new Date().getTime();
long nanoTime = System.nanoTime();
long newtimestamp = javaTime * 1000000 +            // Compute the timestamp
            (event.timestamp - nanoTime);           // in nanos first
String longStr = Long.valueOf(newtimestamp).toString();
String tsString = longStr.substring(0, longStr.length()-6) +// Format the output string
            "." + longStr.substring(longStr.length()-6);    // to have the comma in the
                                                            // correct space.
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接