Javascript减去给出意想不到的值

Javascript subtract giving unexpected value

本问题已经有最佳答案,请猛点这里访问。

我有一个简单的间隔,每次都减去0.1。但是数字序列在3次迭代后变得很奇怪…这就是我所拥有的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function transition_opacity(div_id,opacity){
    opacity = 1; //temporary test
    var IntervId = setInterval(process_transition,30);

    function process_transition(){
        console.log(opacity); //check the value
        opacity = opacity -  0.1
        div_id.style.opacity = opacity;
    if(opacity < 0.0){
            rmv_div(div_id);
            clear();
        }
    }

    function clear(){
         clearInterval(IntervId);
    }
}

控制台日志显示了opacity的值:

1
2
3
4
5
6
7
8
9
10
11
1
0.9
0.8
0.7000000000000001
0.6000000000000001
0.5000000000000001
0.40000000000000013
0.30000000000000016
0.20000000000000015
0.10000000000000014
1.3877787807814457e-16

为什么要做这个疯狂的数字序列=/对我来说似乎没有意义…它的工作精度高达0.8


对于某些无法以浮点存储其数字的方式完美表示的值,浮点数学并不精确。你所看到的只是精确值的细微差别。

这通常可以通过将值四舍五入到一定的小数位数来解决。你可以通过一个简单的谷歌搜索主题来阅读关于浮点精度的尽可能多的信息。一个经典的解决方法是将值四舍五入到一定的小数点。

但是,您的函数实际上仍然可以很好地工作,因为您只需要查找< 0,它仍然可以为您提供适当的迭代次数,即使在值上存在微小的差异。

实际上,您不需要这样的函数才能正常工作,但是如果您想要精确的值,可以将其舍入到一个小数位,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function transition_opacity(div_id,opacity){
    var opacity = 1; //temporary test
    var IntervId = setInterval(process_transition, 30);

    function process_transition(){
        console.log(opacity); //check the value
        opacity = Math.round((opacity -  0.1) * 100) / 100;
        div_id.style.opacity = opacity;
        if (opacity < 0) {
            rmv_div(div_id);
            clear();
        }
    }

    function clear(){
         clearInterval(IntervId);
    }
}

仅供参考,我还声明opacity是一个局部变量。


javascript浮点就是因为这类问题而出名的;这是因为(我引用了这本好书),"采用了IEEE1754二进制浮点算法标准"。

建议的解决方案是使用整数值-对于您的方案,将不透明度值乘以100,进行计算,然后除以100将值转换回十进制值是合乎逻辑的。


这是因为浮点数的表示方式。计算机将尽可能精确地给出0.7的值。然而,因为它不使用基数10,所以它能接近0.7的最精确值将是0.7000000000000001。当你减去另一个0.1,同样的事情也会发生,如此类推。