当前位置: 首页 > 知识库问答 >
问题:

为什么是绳子。在java中将0.1d双精度值格式化为精确的0.1?

唐晗昱
2023-03-14

IEEE 754浮点数是离散的。

public class MyTest2 {
  public static void main(String[] args) {
    //about 1.00000001490116119384765625E-1 in IEEE-754
    float f = 0.1f;
    //about 1.00000000000000005551115123126E-1 in IEEE-754
    double d = 0.1d;
    System.out.println(String.format("double 0.1= %.30f", d));
    System.out.println(String.format("float 0.1 = %.15f", f));
    System.out.println(d+"");
  }
}

查看此代码在IdeOne上的实时运行。通用域名格式。在JDK8中运行时,输出是

double 0.1= 0.100000000000000000000000000000
float 0.1 = 0.100000001490116
0.1

浮点值按预期打印。我预计双倍值0.1d会像1.000000000000000055511151231260一样打印。为什么它在分数部分打印所有零?

如果我把双变量d转换成字符串,它会输出0.1。

System.out.println(d+"");

java如何将0.1d(大约为1.0000000 149011938476565E-1)的neartest浮点值转换为精确的0.1?

共有2个答案

季华茂
2023-03-14

如果你看到java源代码,你会发现

System.out.println(d+"");

将使用以下内容:

Double.toString(d)

这反过来将调用

FloatingDecimal.toJavaFormatString(d)

字符串。格式使用其他机制。这就是为什么你会看到这种行为。

参考文献:

  • https://www.thoughtco.com/concatenation-2034055
  • Java源代码
方夜洛
2023-03-14

Java规范要求这种不完美的值显示。f格式产生的有效位数仅与双精度格式产生的有效位数相同。toString(double)方法将生成零,然后mindlessy追加零以达到要求的精度。

根据文档,对于f格式,如果精度超过小数点后的位数,则为双精度。toString(double)将产生,然后“可以添加零以达到精度”这并没有说明这些零附加到了什么。据推测,它们被附加到Double的字符串中。toString(double)会产生。

Double的文档。toString(double)表示,它会生成“尽可能多的数字,但只会产生尽可能多的数字,以便唯一地将参数值与类型为double的相邻值区分开来”我在这里进一步讨论这个问题。对于0.10000000000000055115123125782702118158340451015625,Double。toString(双精度)产生“0.1”。(相邻的值0.099999999999167332731531132594682276248931884765625和0.100000000000001942890293094023945741355419158935546875都比0.10000000000000055115123125782702118158340411015625远,它们的格式为“0.09999999999999999999”和“0.100000000000002”,因此为“0.1”用于唯一区分0.100000000000000551151231257827021181583404540105625与其邻居。)

因此,系统。出来println(String.format(“double 0.1=%.30f”,d))double中的“0.1”开头。toString(双精度)并附加29个零。

同样,如果将d更改为0.099999999999167332731531132594682276248931884765625,String。format生成“0.099999999999999000000000000”-它将转换为字符串结果并附加零。对于0.100000000000001942890293094023945741355419158935546875,它产生了“0.10000000000000000200000000000000”。

这符合规格。指定的行为无法正确呈现真实值,因此我认为该规范存在缺陷。

顺便说一句,无论请求的精度是大于还是小于双精度的位数,Java规范都很麻烦。toString(double)会产生。在请求权限较小的情况下,Java规范需要双舍入,这可能会增加错误。

 类似资料:
  • 什么是“精度”?使用float和double时,单和双有什么区别?“单精度32位IEEE 754浮点”“双精度64位IEEE 754浮点”是什么意思?

  • 我理解二进制数的理论,所以双精度数的运算是不精确的。但是,在java中,我不知道为什么“(double)65 / 100”是0.65,这在十进制数上是完全正确的,除了0.6500000000004。

  • 我有一系列这样的数据:100 Mbps,200 Mbps,512 Kbps,256 Kbps,100 Mbps, 我需要标准化所有必须在“Mbps”单元中的数据。我正在使用Jaspersoft的ETL软件,该软件允许输入表达式来转换数据。每个数据将被分成两个变量,一个用于存储单位(speedunit),另一个用于存储值(speedvalue),类型为Double。现在,我使用以下表达式: 问题是,

  • 问题内容: 我有一个类似的双精度数字,我需要把它显示为。 如何用Java做到这一点? 问题答案: 结果是 这是我最接近的。

  • 问题内容: 我正在编写一个简单的Java程序。我需要从输入中获取一个字符串并将其分为两部分:1-double 2-string。然后,我需要对double进行简单的计算,并将结果发送到具有特定精度的输出(4)。它工作正常,但是当输入为0时出现问题,则不能正常工作。 例如,对于这些输入,输出将是: 1公斤 输出:2.2046 3.1公斤 输出:6.8343 但是当输入为0时,输出应为0.0000,但

  • 问题内容: 官方Javadoc 说,它返回“等于数学整数”的a,但是为什么它不应该返回a ? 问题答案: 根据同一Javadoc: 如果自变量是或无穷大或正零或负零,则结果与自变量相同。不能用。 最大的价值也比最大的大,所以它必须是一个。