Java中不可表示的浮点数的精确表示

时间:2016-10-16 04:18:29

标签: java floating-point

这似乎是一个非常愚蠢的问题,但我今天遇到了一些神秘且看似美丽的东西。我试着用谷歌搜索,我无法挖掘任何东西。

我知道0.1不能用二进制表示。而且,当我运行以下代码时:

    double g = 1.0; 
    System.out.println(g);
    g = g/10;
    System.out.println(g);
    g = g*3;
    System.out.println(g);

这会产生输出:

1.0
0.1
0.30000000000000004

第一个输出和第三个输出是预期的,但第二个输出是怎么回事?为什么这么正确?这应该是不可能的,然而就是这样。

3 个答案:

答案 0 :(得分:1)

数字促销规则

  1. 如果两个值具有不同的数据类型,Java将自动提升其中一个值 两种数据类型中较大的一种。
  2. 如果其中一个值是整数而另一个是浮点值,则Java将自动生成 将积分值提升为浮点值的数据类型。
  3. 较小的数据类型,即byte,short和char,随时首先提升为int 它们与Java二进制算术运算符一起使用,即使两个操作数都不是 中间体
  4. 发生所有促销并且操作数具有相同的数据类型后,结果 - 值将与其提升的操作数具有相同的数据类型。

答案 1 :(得分:1)

  

为什么这样,是的,对吗?

如您所述,许多十进制浮点数不能表示为二进制浮点数,反之亦然

当你写这样的陈述时:

double g = 0.1;

将十进制值转换为最接近的二进制浮点值。然后当你像这样打印它

System.out.println(g);

格式化程序根据以下规则生成最接近的十进制浮点值:

  

小数部分必须打印多少位数?必须至少有一个数字来表示小数部分,并且除此之外必须有多个,但只有多少,更多的数字才能唯一地将参数值与double类型的相邻值区分开来。

(参考:Double.toString(double) javadoc

这意味着您将经常获取您开始使用的十进制数的精确十进制表示。

简单来说,从十进制转换为二进制时的错误与从二进制转换为十进制时的错误相同。错误“取消”。

现在,这并不总是发生。通常,计算中的累积误差足够大,十进制(和二进制)结果中的误差将在输出中显而易见。

答案 2 :(得分:0)

让我们逐行逐步完成计算:

$("#communitymembers").append(memberslist); 
$container.isotope();

g是完全代表1.0的float64数字。

double g = 1.0;

右操作数转换为double,因此精确到10.0。

除法运算以无限精度(概念上)执行,然后四舍五入到最接近的float64数字作为结果。

确切的答案显然是0.1。但最接近的float64数字为0.1正好是7205759403792794/256。

因此g = 0.10000000000000000555111512312578 ...(更多数字)。如果要打印全精度精确值,请查看新的BigDecimal(g)。

g = g / 10;

同样,右操作数被转换为3.0精确。我们将0.1000000000000000055511151231257(...)乘以3得到0.3000000000000000166533453693773(...)。

现在g的值恰好是5404319552844596/2 54