如何让Java格式化一个双精度数值为-3.2而不是-3.1999999999999953?

8

我的应用程序产生的双精度浮点数,使用Double.toString()方法会产生"-3.1999999999999953",但我期望它应该是"-3.2"。

实际上,这些双精度浮点数是从JScience的Amount#getEstimatedValue()中获取的。

我不想为精度设置任意数字,因为我不知道有多少位数字是有效的,但我也不想生成以"99999999.*"结尾的数字。

如何避免这个问题将双精度浮点数转换为字符串?


3
不要使用没有有限二进制展开的数值。 - Kerrek SB
1
这并不是很有帮助,我无法控制我必须处理的数字。 - sanity
是的,我需要能够处理浮点数。 - sanity
4
如果你不知道需要什么精度,那么你怎么能确定“-3.1999999999999953”不是准确的值呢? - Toomai
你不能既要拥有蛋糕,又想吃掉它。 - David Heffernan
显示剩余5条评论
3个回答

7

推荐解决方案

BigDecimal.valueOf (hisDouble).toPlainString ()

在本文的最后一节中提供的黑客技巧是我尝试解决问题时首先想到的。

然后,一个朋友问我正在做什么,并表示OP最好使用BigDecimal,于是我陷入了沮丧的状态。

但我将在本文中保留这个黑客技巧,以便全世界都能看到我有时会变得多么愚蠢。


在打印时可以使用System.out.format

以下代码片段将会将yourDecimal的值舍入到小数点后一位,然后打印该值。

Double yourDouble = -3.1999999999999953;
System.out.format ("%.1f", yourDouble);

输出

-3.2

史上最愚蠢的黑客攻击

  public static String fixDecimal (Double d) {
    String  str = "" + d;
    int    nDot = str.indexOf ('.');

    if (nDot == -1)
      return str;

    for (int i = nDot, j=0, last ='?'; i < str.length (); ++i) {
      j = str.charAt (i) == last ? j+1 : 0;

      if (j > 3)
        return String.format ("%."+(i-nDot-j-1)+"f", d);

      last = str.charAt (i);
    }

    return str;
  }

...

Double[] testcases = {
  3.19999999999953,
  3.145963219488888,
  10.4511111112,
  100000.0
};

for (int i =0; i < testcases.length; ++i)
  System.out.println (
    fixDecimal (testcases[i]) + "\n"
  );

输出

3.2
3.1459632195
10.45
100000.0

1
原帖作者表示她不想指定精度级别。 - Kerrek SB
1
这将输出内容到标准输出,对于 OP 来说可能并不太有帮助...? - Brian
哦,我没有注意到那部分,抱歉 - 我会修改我的帖子为更相关的内容。 - Filip Roséen - refp

4

使用 BigDecimal

System.out.println(BigDecimal.valueOf(-3.2d).toPlainString());

输出:

-3.2

3

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