Double.toString 总是产生与双文字完全相同的结果吗?

问题描述 投票:0回答:4

Double.toString(0.1)
产生“0.1”,但 0.1 是浮点数。

浮点数无法在程序语言中精确表示,但 Double.toString 会产生精确的结果(0.1),它是如何做到的?它总是产生数学上等于double字面量的结果吗?

假设文字是双精度的。

这是我看到的问题:

当使用Apache POI读取excel文件时,

XSSFCell.getNumericCellValue
只能返回
double
,如果我使用
BigDecimal.valueOf
将其转换为
BigDecimal
,总是安全的,为什么?

java floating-point
4个回答
4
投票

Double.toString 产生精确的结果 (0.1),它是如何做到的,它总是产生数学上等于 double 文字的结果吗?

如果

Double.toString(X)

 是有效数字不超过 15 位的十进制数字,并且在 
X
 格式的范围内,则 
X
将始终生成等于
Double
的数字。

这有两个原因:

  1. Double
    格式(IEEE-754二进制64)具有足够的精度,因此始终可以区分15位十进制数字。
  2. Double.toString
    通常不会显示准确的
    Double
    值,而是 生成将数字与附近
    Double
    值区分开来所需的最少有效数字。

例如,源文本中的文字

0.1
会转换为
Double
值 0.1000000000000000055511151231257827021181583404541015625。但默认情况下
Double.toString
不会产生所有这些数字。它使用的算法产生“0.1”,因为这足以唯一区分 0.1000000000000000055511151231257827021181583404541015625 与其两个邻居,即 0.09999999999999999167332731531132594682 276248931884765625和0.10000000000000001942890293094023945741355419158935546875。两者都离 0.1 更远。

因此,

Double.toString(1.234)
Double.toString(123.4e-2)
Double.toString(.0001234e4)
都会产生“1.234”——一个数字,其值等于所有原始十进制数字(在转换为
Double
之前),尽管它的形式与其中一些。

当使用Apache POI读取excel文件时,

XSSFCell.getNumericCellValue
只能返回
double
,如果我使用
BigDecimal.valueOf
将其转换为
BigDecimal
,总是安全的,为什么?

如果正在检索的单元格值不能表示为

Double
,则
XSSFCell.getNumericCellValue
必须更改它。根据记忆,我认为
BigDecimal.valueOf
将产生返回的
Double
的确切值,但我不能对此做出权威的评价。这是一个独立于
Double
Double.toString
行为的问题,因此您可以将其作为一个单独的问题来问。


2
投票

10e-5d
是相当于 10^-5
的双精度文字
Double.toString(10e-5d)
返回
"1.0E-4"


2
投票

嗯,

double
类型的精度有限,因此如果您在浮点后添加足够的数字,其中一些数字将被截断/舍入。

例如:

System.out.println (Double.toString(0.123456789123456789))

打印

0.12345678912345678

0
投票

我同意Eric Postpischil的回答,但另一种解释可能会有所帮助。

对于每个双数,都有一个根据半偶数规则舍入到它的实数范围。对于0.1000000000000000055511151231257827021181583404541015625,将0.1四舍五入到双精度的结果,范围是[0.099999999999999998612221219218554324470460414 886474609375,0.100000000000000012490009027033011079765856266021728515625].

任何实数算术值在该范围内的双精度文字都具有与 0.1 相同的双精度值。

Double.toString(x)
返回转换为
x
且具有最少小数位数的范围内实数的字符串表示形式。选择该范围内的任何实数可确保使用 Double.toString 将双精度型转换为字符串,然后使用半偶规则将字符串转换回双精度型的往返过程恢复原始值。

System.out.println(0.100000000000000005);
打印“0.1”,因为 0.100000000000000005 位于四舍五入到与 0.1 相同的双精度的范围内,而 0.1 是该范围内小数位数最少的实数。

这种效果很少可见,因为除“0.1”之外具有该范围内的实数值的文字很少见。由于精度较低,浮动的情况更为明显。

System.out.println(0.100000001f);
打印“0.1”。

© www.soinside.com 2019 - 2024. All rights reserved.