JavaScript 浮点数运算的精度问题及解决

在 JavaScript 中整数和浮点数都属于 Number 数据类型,当浮点数做数学运算的时候,你经常会发现一些问题,举几个例子:

0.1 + 0.2 = 0.30000000000000004

console.log(0.1 + 0.2) = 0.30000000000000004

1.5 - 1.2 = 0.30000000000000004

19.9 * 100 = 1989.9999999999998

0.3 / 0.1 = 2.9999999999999996

参见下图:

怎么回事?JavaScript 算错了吗?

不是错误,原因在于浮点数(Floating-point Number)是对实数的一种近似表示。

这个问题并不只是在 Javascript 中才会出现,几乎所有的编程语言都采用了 IEEE-754 浮点数表示法,下面是Python语言的情况:

关于IEEE754浮点更多情况可见:IEEE754浮点表示小结 https://zhuanlan.zhihu.com/p/615232196

在此我们不展开介绍,而主要介绍JavaScript中如何应对这种情况,这里给出一些解决方案。

★使用一些第三方库,如 Decimal.js 等,提供了更高精度的浮点数运算功能。这些库可以处理更复杂的运算,并提供更高的精度。

当你在浏览器环境中使用 Decimal.js 库时,你可以按照以下步骤进行操作:

下载 Decimal.js 库文件。你可以在 Decimal.js 的官方网站(文档:https://mikemcl.github.io/decimal.js/ 下载:https://github.com/MikeMcl/decimal.js )上找到下载链接。

将下载的 Decimal.js 文件保存到你的项目中的合适位置。

在你的 HTML 文件中添加以下代码来引入 Decimal.js 库:

<script src="path/to/decimal.js"></script>

确保将 path/to/decimal.js 替换为实际的文件路径。

使用 <script> 标签引入 Decimal.js 库文件的在线版本:

<script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.2.1/decimal.min.js"></script>

使用在线版本方便一些,但不能断网

在你的 JavaScript 代码中,你可以使用 Decimal 对象来执行精确的数学运算。以下是一个简单的例子:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.2.1/decimal.min.js"></script>
</head>
<body>
  <script>
    // 创建 Decimal 对象
    var num1 = new Decimal(0.1);
    var num2 = new Decimal(0.2);

    // 执行数学运算
    var sum = num1.plus(num2);
    var product = num1.times(num2);

    // 打印结果
    console.log(sum.toString()); // 输出: 0.3
    console.log(product.toString()); // 输出: 0.02
  </script>
</body>
</html>

在这个例子中,我们首先引入了 Decimal.js 库。然后,我们创建了两个 Decimal 对象 num1 和 num2,并使用 plus 方法计算它们的和,使用 times 方法计算它们的乘积。最后,我们使用 toString 方法将结果转换为字符串并打印出来。

这样在浏览器环境中使用Decimal.js等库进行精确的数学运算,有点麻烦,也可以使用一些技巧来处理浮点数运算。下面介绍这些技巧。

★将浮点数转换为整数进行运算,然后再将结果转换回浮点数。例如,使用整数运算:将浮点数转换为整数进行运算,然后再将结果转换回浮点数。例如,可以将浮点数乘以一个较大的倍数,进行整数运算,然后再除以相同的倍数,得到最终结果。

(0.1 * 10 + 0.2 * 10) / 10;  //输出 0.3

★使用 JavaScript 的内置函数 toFixed() 来控制浮点数的小数位数。这个函数会将浮点数四舍五入到指定的小数位数,并返回一个字符串表示的结果。

使用内置函数toFixed():toFixed() 函数可以将浮点数四舍五入到指定的小数位数,并返回一个字符串表示的结果。

    1. + 0.2).toFixed(1);  //输出'0.3'

最后,给出一个有点意思的例子

实现自动出题(加减乘除)四则运算的并能判断用户输入答案对错,效果图如下:

HTML网页文件源码:

<!DOCTYPE html>
<html>
<head>
    <title>四则运算自动出题</title>
    <script>
        //generateQuestion() 函数用于生成一个数学问题
        function generateQuestion() {
            var num1 = Math.floor(Math.random() * 10) + 1;
            var num2 = Math.floor(Math.random() * 10) + 1;
            var operator = Math.floor(Math.random() * 4); // 0: +, 1: -, 2: *, 3: /
            var question;
            var answer;

            switch (operator) {
                case 0:
                    question = num1 + " + " + num2;
                    answer = num1 + num2;
                    break;
                case 1:
                    question = num1 + " - " + num2;
                    answer = num1 - num2;
                    break;
                case 2:
                    question = num1 + " * " + num2;
                    answer = num1 * num2;
                    break;
                case 3:
                    question = num1 + " / " + num2;
                    //answer = num1 / num2;
                    answer = (num1 / num2).toFixed(2);  //保留两位小数
                    break;
            }

            document.getElementById("question").innerHTML = question;
            document.getElementById("answer").value = "";  //用户回答用
            document.getElementById("result").innerHTML = "";
            document.getElementById("correctAnswer").value = answer; //正确答案存储在隐藏的输入框中
        }
        
        //checkAnswer() 函数用于检查用户输入的答案是否正确。
        function checkAnswer() {
            var userAnswer = parseFloat(document.getElementById("answer").value);
            var correctAnswer = parseFloat(document.getElementById("correctAnswer").value);
            var result;

            if (userAnswer === correctAnswer) {
                result = "回答正确!";
            } else {
                result = "回答错误!正确答案是 " + correctAnswer;
            }

            document.getElementById("result").innerHTML = result;
        }
    </script>
</head>
<body>
    <h1>四则运算题目</h1>
    <p>实现自动出题(加减乘除)四则运算的并能判断用户输入答案对错,除法结果保留两位小数</p>
    <p>用户可以点击下一题按钮生成新的题目。每次点击下一题按钮时,JavaScript代码会生成新的题目</p>
    <p id="question"></p>
    <input type="number" id="answer" placeholder="请输入答案">
    <button onclick="checkAnswer()">提交</button>
    <button onclick="generateQuestion()">下一题</button>
    <p id="result"></p>
    <input type="hidden" id="correctAnswer">
    <script>
        generateQuestion();
    </script>
</body>
</html>

OK! 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐