Java Double.toString是否总是生成与Double literal完全相同的结果?

Java Double.toString是否总是生成与Double literal完全相同的结果?,java,floating-point,Java,Floating Point,Double.toString(0.1)生成“0.1”,但0.1是一个浮点数 浮点数在程序语言中不能精确表示,但Double.toString会产生精确的结果(0.1),它是如何做到的,它总是产生数学上等于双文本的结果吗 假设文字是双精度的 以下是我看到的问题: 当使用Apache POI读取excel文件时,XSSFCell.getNumericCellValue只能返回double,如果我使用BigDecimal.valueOf将其转换为BigDecimal,这总是安全的吗?为什么?10e-

Double.toString(0.1)
生成“0.1”,但0.1是一个浮点数

浮点数在程序语言中不能精确表示,但Double.toString会产生精确的结果(0.1),它是如何做到的,它总是产生数学上等于双文本的结果吗

假设文字是双精度的

以下是我看到的问题:


当使用Apache POI读取excel文件时,
XSSFCell.getNumericCellValue
只能返回
double
,如果我使用
BigDecimal.valueOf
将其转换为
BigDecimal
,这总是安全的吗?为什么?

10e-5d
是一个相当于10^-5的双字面值
Double.toString(10e-5d)
返回
“1.0E-4”

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

例如:

System.out.println (Double.toString(0.123456789123456789))
印刷品

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

Double。如果
XXX
是具有15个或更少有效数字的十进制数字,并且在
Double
格式的范围内,则toString(XXX)
将始终生成一个等于
XXX
的数字

原因有两个:

  • Double
    格式(IEEE-754 binary64)具有足够的精度,因此始终可以区分15位十进制数字
  • Double.toString
    不显示确切的
    Double
    值,而是显示
  • 例如,源文本中的文本
    0.1
    被转换为
    Double
    值0.1000000000000005555115123125782702118158340451015625。但是默认情况下,
    Double.toString
    不会生成所有这些数字。它使用的算法产生“0.1”,因为这足以将0.1000000000000005555115123125782702118158340451015625与其两个邻居(0.099999999999167332731531132594682276248931884765625和0.100000000000001942890293094023945741355419158935546875)唯一区分开来。这两个值都远离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
    行为的问题,因此您可以将其作为一个独立的问题提问。

    我同意,但另一种解释可能会有所帮助

    对于每一个双精度数,都有一系列实数,根据半偶数规则进行四舍五入。对于0.10000000000000055115123125782702118158340451015625,四舍五入0.1到一个双精度的结果,范围是[0.09999999999861222219554324470460414886474609375,0.1000000000000012490009090907301079765626602178515625]

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

    Double.toString(x)
    返回转换为
    x
    且小数位数最少的范围内实数的字符串表示形式。选取该范围内的任何实数可确保使用double.toString将double转换为字符串,然后使用round-half-偶数规则将字符串转换回double的往返过程会恢复原始值

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


    这种效果很少可见,因为实数值在范围内的“0.1”以外的文字很少。由于精度较低,所以对于float更为明显<代码>系统输出打印项次(0.10000001F)打印“0.1”。

    双精度。如果您真的这么问,toString(0.10)
    将不会生成
    “0.10”
    。您的意思是字符串如何精确打印
    0.1
    ,其中双精度的数字不精确
    0.1
    @Eklavya是的。它是否总是为文字输入打印精确的结果?中的双精度值没有精确表示,但赋值后双精度值是精确的。有道理吗?@Eklavya
    双d=0.1
    d
    没有准确存储该值。如果使用
    new BigDecimal(0.1)
    进行测试,则将其打印出来,结果为
    0.10000000000000055115123125782702118158340451015625
    。谢谢您的回答。也许我的问题不清楚。如果数字是有限的,在双精度,并且不考虑尾随0。结果在数学上总是等于文字吗?@ss。你的问题没有提到限制数字。也许你应该修改你的问题,使之精确。如果要限制数字,必须指定限制。