【问题标题】:how does Java convert floats to stringsJava如何将浮点数转换为字符串
【发布时间】:2014-06-16 20:41:26
【问题描述】:

这是我正在查看的内容:

float p=1.15f;
BigDecimal bdp=new BigDecimal(p);
float q=1.1499999f;
float r=1.14999999f;

System.out.println(p);   //1.15
System.out.println(bdp); //1.14999997615814208984375
System.out.println(q);   //1.1499999
System.out.println(r);   //1.15

所以我知道“p”1.15 的十进制值不能用二进制精确表示。
所以大的小数“bdp”输出对我来说非常有意义......这是浮点数的实际值。

问题 1
当浮点“p”转换回输出字符串(如 1.15)时,该舍入如何/在哪里发生(从内部 1.149..375 值到 1.15)?

它在文档中的哪里指定? toString javadoc 并没有真正的帮助(至少我是这样)。

我确实在the language spec看到了这个:

float 和 double 类型的元素是那些可以 使用 IEEE 754 32 位单精度和 64 位表示 分别为双精度二进制浮点格式。

Wikipedia's IEEE 754 article 给出了这个:

这给出了 6 到 9 位有效十进制数字的精度(如果 最多 6 位有效小数的十进制字符串转换为 IEEE 754个单精度再转换回相同的个数 有效小数,则最终字符串应与原始字符串匹配;

问题 2
所以看起来这就是 Java/IEEE 754 浮点数应该如何工作的?

我可以保证浮点/字符串转换/表示的准确性达到一定位数(如“p”和“q”),如果超过该位数,Java 将进行一些舍入以进行显示(如对于“r”)?

感谢您的帮助。

【问题讨论】:

  • 除非你从事科学工作!停止使用浮点数。
  • 正确。我们在代码中使用 BigDecimals。但是我们从另一个系统得到双打,我需要了解这些细节,这样我才能确保我正在处理尽可能准确的数据。谢谢
  • 如果您对此类问题感兴趣,请考虑使用System.out.println(new BigDecimal(someFloat)); 获取someFloat 的精确十进制表示。

标签: java floating-point


【解决方案1】:

我认为这是描述您正在查看的行为的 Javadoc 的相关部分(来自 static String toString(float) 方法):

m 或 a 的小数部分必须打印多少位?必须至少有一个数字来表示小数部分,除此之外,必须有尽可能多的数字,但仅能将参数值与浮点类型的相邻值唯一区分开来。

解释一下:浮点类型的 toString 方法通常会生成最短的十进制表示,可以明确地识别浮点数的真实值。

示例程序来说明:

import java.math.BigDecimal;

public class FloatTest {

  static void show(float f) {
    BigDecimal f_exact = new BigDecimal(f);
    System.out.println("---");
    System.out.println("String value: " + f);
    System.out.println("Exact value:  " + f_exact);
    System.out.println("Delta:        " + 
        new BigDecimal("1.15").subtract(f_exact));
  }

  public static void main(String[] args) {
    show(1.15f);
    show(Math.nextUp(1.15f));
  }
}

输出:

---
String value: 1.15
Exact value:  1.14999997615814208984375
Delta:        2.384185791015625E-8
---
String value: 1.1500001
Exact value:  1.150000095367431640625
Delta:        -9.5367431640625E-8

【讨论】:

  • 好的,谢谢,你说得对。我之前读过,但直到现在才真正点击。
【解决方案2】:

感谢 mttdbrd ... 有帮助。从您的第一段开始,我认为我的问题的答案是:是的,Java 根据 IEEE 规范在内部进行此舍入。

下面是一个程序的输出,让我可以看到一些实际的舍入:

-------------------------------------------
string            1.49999
bigdec of float   1.499989986419677734375
float back to str 1.49999
-------------------------------------------
string            1.4999991
bigdec of float   1.49999904632568359375
float back to str 1.499999
-------------------------------------------
string            1.4999992
bigdec of float   1.49999916553497314453125
float back to str 1.4999992
-------------------------------------------
string            1.4999993
bigdec of float   1.4999992847442626953125
float back to str 1.4999993
-------------------------------------------
string            1.4999994
bigdec of float   1.49999940395355224609375
float back to str 1.4999994
-------------------------------------------
string            1.4999995
bigdec of float   1.499999523162841796875
float back to str 1.4999995
-------------------------------------------
string            1.4999996
bigdec of float   1.49999964237213134765625
float back to str 1.4999996
-------------------------------------------
string            1.4999997
bigdec of float   1.49999964237213134765625
float back to str 1.4999996
-------------------------------------------
string            1.4999998
bigdec of float   1.4999997615814208984375
float back to str 1.4999998
-------------------------------------------
string            1.4999999
bigdec of float   1.49999988079071044921875
float back to str 1.4999999
-------------------------------------------
string            1.15
bigdec of float   1.14999997615814208984375
float back to str 1.15
-------------------------------------------
string            1.49999964237213134765626
bigdec of float   1.49999964237213134765625
float back to str 1.4999996

如果有人想要,这里是程序:

public static void floatAccuracy3()
{
    printFloatAndBigDec("1.49999");
    for (int i = 1; i < 10; i++) {
        String s="1.499999";
        s+=i;
        printFloatAndBigDec(s);         
    }
    printFloatAndBigDec("1.15");
    printFloatAndBigDec("1.49999964237213134765626");
}

public static void printFloatAndBigDec(String s)
{
    Float f=new Float(s);
    BigDecimal bdf=new BigDecimal(f);
    System.out.println("-------------------------------------------");
    System.out.println("string            "+s);
    System.out.println("bigdec of float   "+bdf);
    System.out.println("float back to str "+f);
}

还有一些其他链接,以防它们对其他研究这些东西的人有所帮助:

【讨论】:

    【解决方案3】:

    来自 JLS,4.2.4。浮点运算:

    Java 编程语言要求浮点运算 表现得好像每个浮点运算符都对其浮点进行舍入 结果到结果精度。不精确的结果必须四舍五入到 最接近无限精确结果的可表示值;如果 两个最接近的可表示值同样接近,一个具有它的 选择最低有效位零。这是 IEEE 754 标准的 默认舍入模式称为“四舍五入”。

    Java 编程语言在转换 将浮点值转换为整数(第 5.1.3 节),在这种情况下,其作用为 虽然数字被截断,丢弃尾数位。 向零舍入会在其结果中选择最接近格式的值 到并且幅度不大于无限精确的结果。

    【讨论】:

      猜你喜欢
      • 2011-11-25
      • 1970-01-01
      • 2018-02-15
      • 2011-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多