【前端怪谈】js中为什么0.1+0.2 !== 0.3

news/2024/7/19 12:59:17 标签: js, 前端

文章目录

  • 前言
  • 一、问题原因
  • 二、解决办法
  • 三、大数相加
    • 1、BigInt
    • 2、大数相加
  • 总结


前言

下面大家先来看一下这行诡异的代码,猜猜会输出什么

console.log(0.1 + 0.2);

在这里插入图片描述
是不是和所想的不太一样?下面我们来探索一下为什么它会这样吧。

一、问题原因

在计算机中数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。

在JS中数字采用的IEEE 754的双精度标准进行存储(存储一个数值所使用的二进制位数比较多,精度更准确)

在此标准下,无法精确表示的非常大的整数将自动四舍五入。确切地说,JS 中的 Number类型只能安全地表示 -9007199254740991(-(2^53-1))9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能失去精度。

在定点数中,如果我们以8位二进制来存储数字。

对于整数来说,十进制的35会被存储为: 00100011 其代表 2^5 + 2^1 + 2^0。
对于纯小数来说,十进制的0.375会被存储为: 0.011 其代表 1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375

对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011…由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。

0.1和0.2在转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉,此时就已经出现了精度的损失,相加后因浮点数小数位的限制而截断的二进制数字在转换为十进制就会变成0.30000000000000004。

二、解决办法

解决方法很简单,我们只要避免0.1直接和0.2相加就够了。

	  let a = 0.1;
      let b = 0.2;
      const add = (a, b) => {
        return (a * 10 + b * 10) / 10;
      };
      console.log(add(a, b));

我们先将两个数分别乘以10相加后再除以10就能得到结果啦。(这只是一道数学题哦)

三、大数相加

前面我们提到JS 中的 Number类型只能安全地表示 -9007199254740991(-(2^53-1))9007199254740991(2^53-1)之间的整数,如果我们需要使用比它大的数字该怎么办呢?

1、BigInt

BigInt是一种新的数据类型,用于当整数值大于 Number数据类型支持的范围时。这种数据类型允许我们安全地对大整数执行算术操作,表示高分辨率的时间戳,使用大整数id,等等,而不需要使用库。

	  let a = 321984671983710923709123709123709123720917312n;
      let b = 2130192379012379102309123091230912309217309127309n;
      console.log(a + b);

在这里插入图片描述

2、大数相加

虽然BigInt已经能够解决此类问题了,但是它的兼容性并不是很好
在这里插入图片描述
那我们也想大数相加怎么办呢?

既然没有轮子,我们就自己造一个!

function add(str1, str2) {
        //判断最大长度
        const len1 = str1.length;
        const len2 = str2.length;
        const len = Math.max(len1, len2);
        // 定义字符串
        let arr = "";
        // 进位数
        let w = 0;
        // 从最小位开始进行位运算
        for (let i = 0; i < len; i++) {
          // 根据位次取出相应数字
          let num1 = str1.charAt(len1 - i - 1);
          let num2 = str2.charAt(len2 - i - 1);
          // 两数相加
          let sum = Number(num1) + Number(num2);
          // 两数之和加上进位数
          sum = sum + w;
          // 重置进位数
          w = 0;
          // 对两数之和进行判断
          if (sum >= 10) {
            w++;
            sum = sum - 10;
          }
          arr = sum + arr;
          if (i === len - 1 && w === 1) {
            arr = w + arr;
          }
        }
        return arr;
      }
console.log(add('709123907123170293012930790192321','79124309123091273093217092137091270217123121'));

在这里插入图片描述
大功告成!

总结

以上就是今天要讲的内容,前端怪谈将带你一起探索前端中的"怪事"。


http://www.niftyadmin.cn/n/861666.html

相关文章

【前端优化】超详细!带你体验常用的前端优化手段

文章目录前言一、图片懒加载原因判断是否进入可视区方案一: clientHeight、scrollTop 和 offsetTop方案二&#xff1a;getBoundingClientRect二、防抖与节流三、路由和组件懒加载原因使用实例路由懒加载:组件懒加载四、图片预加载原因五、使用前端缓存强缓存协商缓存六、减少回…

【前端怪谈】为什么要用setTimeout模拟setInterval

文章目录前言一、setInterval存在的问题1.问题复现2.问题分析二、setInterval缺点及setTimeout1.setInterval缺点2.为什么setTimeout能取代setTimeout实现setInterval总结前言 大家都知道&#xff0c;setTimeout是延迟执行函数&#xff0c;而setInterval就像一个定时器&#x…

深入透析Promise实现细节(含手撕阶段)

文章目录前言一、Promise是什么&#xff1f;二、Promise核心逻辑实现1.基本原理2.新建类promise类&#xff0c;传入执行器executor3.传入resolve和reject方法4.then方法的简单实现5.完整代码及验证6.代码改进三.链式调用1.链式调用实现的基本思路2.then方法返回promise对象3.re…

闭包真的还会造成内存泄露吗?你不知道的闭包与垃圾回收!

文章目录前言一、闭包是什么&#xff1f;二、闭包有什么好处和坏处呢&#xff1f;1.好处2.坏处二、闭包会造成内存泄露吗&#xff1f;1.前言2.闭包会造成内存泄露吗&#xff0c;如果会为什么还会再react hooks中大量使用呢&#xff1f;三、为什么ie8及之前会造成内存泄露&#…

【JS垃圾回收】带你探索垃圾回收机制和Chrome V8垃圾回收机制

文章目录前言一、什么是垃圾回收&#xff1f;1.基本思路2.为什么要进行垃圾回收二、怎样进行垃圾回收1.标记清除优点缺点2.引用计数优点缺点三、Chrome V8垃圾回收机制1.为什么需要优化垃圾回收算法2.基本概念3.新生代垃圾回收器 - Scavenge4.老生代垃圾回收 - Mark-Sweep &…

深入透析Promise几种方法(含手撕思路讲解及坑点)

文章目录前言一、Promise.all()1.介绍2.实例状态全为fulfilled状态有一个为rejected3.代码实现思路代码二、Promise.race()1.介绍2.实例3.代码实现思路代码总结前言 前面我们简单实现了一个promise&#xff0c;不懂的同学&#xff0c;传送门&#xff1a;深入透析Promise 那么…

【Diff算法图解】带你探索React、Vue2.x的Diff算法

文章目录前言一、Virtual DOM&#xff08;虚拟dom&#xff09;二、React Diff实现思想移动节点增加节点移除节点React Diff的缺陷三、Vue2.X Diff实现思想移动节点特殊情况增加节点移除节点总结前言 我们都知道&#xff0c;在框架中&#xff0c;当dom节点发生变化时&#xff0…

CSS初学的简单样式

CSS导航条 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><style type"text/css">*{margin: 0;padding: 0;}.nav{list-style: none;background-color: blueviolet;width: 500px;margin:50p…