iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >前端大数的运算及相关知识有哪些
  • 581
分享到

前端大数的运算及相关知识有哪些

2024-04-02 19:04:59 581人浏览 薄情痞子
摘要

本篇内容主要讲解“前端大数的运算及相关知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“前端大数的运算及相关知识有哪些”吧! 背景前段时间我在公

本篇内容主要讲解“前端大数的运算及相关知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“前端大数的运算及相关知识有哪些”吧!

 背景

前段时间我在公司的项目中负责的是权限管理这一块的需求。需求的大概内容就是系统的管理员可以在用户管理界面对用户和用户扮演的角色进行增删改查的操作,然后当用户进入主应用时,前端会请求到一个表示用户权限的数组usr_permission,前端通过usr_permission来判断用户是否拥有某项权限。

这个usr_permission是一个长度为16的大数字符串数组,如下所示:

const usr_permission = [   "17310727576501632001",     "1081919648897631175",     "4607248419625398332",     "18158795172266376960",     "18428747250223005711",     "17294384420617192448",     "216384094707056832",     "13902625308286185532",     "275821367043",     "0",     "0",     "0",     "0",     "0",     "0",     "0", ]

数组中的每一个元素可以转成64位的二进制数,二进制数中的每一位通过0和1表示一种权限,这样每一个元素可以表示64种权限,整个usr_permission就可以表示16*64=1024种权限。后端之所以要对usr_permission进行压缩,是因为后端采用的是微服务架构,各个模块在通信的过程中通过在请求头中加入usr_permission来做权限的认证。

数组usr_permission的第0个元素表示第[0, 63]号的权限,第1个元素表示第[64, 127]号的权限,以此类推。比如现在我们要查找第220号权限:

const permission = 220 // 查看销售出库 const usr_permission = [   "17310727576501632001",     "1081919648897631175",     "4607248419625398332",     "18158795172266376960",     "18428747250223005711",     "17294384420617192448",     "216384094707056832",     "13902625308286185532",     "275821367043",     "0",     "0",     "0",     "0",     "0",     "0",     "0", ]  // "18158795172266376960" 表示第193号~第256号权限 // 1111 1100 0000 0000 1111 1111 1111 1111 1111 0000 0000 0011 1111 1111 0000 0000 // 220 % 64 = 28 // 0000 0000 0000 0000 0000 0000 0000 1111 1100 0000 0000 1111 1111 1111 1111 1111 // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 // ------------------------------------------------------------------------------- // 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
  • 从usr_permission中我们得知第220号权限由第3个元素"18158795172266376960"表示。

  • 我们将"18158795172266376960"转成二进制得到1111 1100 0000 0000 1111 1111 1111 1111 1111 0000 0000 0011 1111 1111 0000 0000。

  • 将220除以64得到余数28,也就是说二进制数1111 1100 0000 0000 1111 1111 1111 1111 1111 0000 0000 0011 1111 1111 0000 0000从右数的第28位表示第220号权限。

  • 我们可以将二进制数1111 1100 0000 0000 1111 1111 1111 1111 1111 0000 0000 0011 1111 1111 0000 0000右移28位,将表示第220号权限的位数推到最低位。

  • 然后将二进制数与1进行按位与操作,如果当前用户拥有第220号权限,则最后得到的结果为1,反之为0。

以上就是前端查找权限的大致过程,那么这个代码要怎么写呢?在编写代码之前,我们先来复习一下javascript大数相关的知识,了解编写代码的过程中会遇到什么问题。

IEEE 754标准

在计算机组成原理这门课里我们学过,在以IEEE 754为标准的浮点运算中,有两种浮点数值表示方式,一种是单精度(32位),还有一种是双精度(64位)。

前端大数的运算及相关知识有哪些

在IEEE 754标准中,一个数字被表示成 +1.0001x2^3 这种形式。比如说在单精度(32位)表示法中,有1位用来表示数字的正负(符号位),8位用来表示2的幂次方(指数偏移值E,需要减去一个固定的数字得到指数e),23位表示1后面的小数位(尾数)。

比如0 1000 0010 0001 0000 0000 0000 0000 000,第1位0表示它是正数,第[2, 9]位1000 0010转换成十进制就是130,我们需要减去一个常数127得到3,也就是这个数字需要乘以2的三次方,第[10, 32]位则表示1.0001 0000 0000 0000 0000 000,那么这个数字表示的就是二级制中的 +1.0001*2^3 ,转换成十进制也就是8.5。

前端大数的运算及相关知识有哪些

同理,双精度(64位)也是一样的表现形式,只是在64位中有11位用来表示2的幂次方,52位用来表示小数位。

JavaScript 就是采用IEEE754 标准定义的64 位浮点格式表示数字。在64位浮点格式中,有52位可以表示小数点后面的数字,加上小数点前面的1,就有53位可以用来表示数字,也就是说64位浮点可以表示的最大的数字是 2^53-1 ,超过 2^53-1 的数字就会发生精度丢失。因为2^53用64位浮点格式表示就变成了这样:

符号位:0 指数:53 尾数:1.000000...000 (小数点后一共52个0)

小数点后面的第53个0已经被丢弃了,那么 2^53+1 的64位浮点格式就会变得和 2^53 一样。一个浮点格式可以表示多个数字,说明这个数字是不安全的。所以在JavaScript中,最大的安全数是 2^53-1 ,这样就保证了一个浮点格式对应一个数字。

0.1 + 0.2 !== 0.3

有一道很常见的前端面试题,就是问你为什么JavaScript中0.1+0.2为什么不等于0.3?0.1转换成二进制是0.0 0011 0011 0011 0011 0011 0011 ... (0011循环),0.2转换成二进制是0.0011 0011 0011 0011 0011 0011 0011 ... (0011循环),用64位浮点格式表示如下:

// 0.1 e = -4; m = 1.1001100110011001100110011001100110011001100110011010 (52位)  // 0.2 e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52位)

然后把它们相加:

e = -4; m = 1.1001100110011001100110011001100110011001100110011010 (52位) + e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52位)  // 0.1和0.2指数不一致,需要进行对阶操作 // 对阶操作,会产生精度丢失 // 之所以选0.1进行对阶操作是因为右移带来的精度丢失远远小于左移带来的溢出 e = -3; m = 0.1100110011001100110011001100110011001100110011001101 (52位) + e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52位)   e = -3; m = 10.0110011001100110011001100110011001100110011001100111 (52位)  // 发生精度丢失 e = -2; m = 1.00110011001100110011001100110011001100110011001100111 (53位)

我们看到已经溢出来了(超过了52位),那么这个时候我们就要做四舍五入了,那怎么舍入才能与原来的数最接近呢?比如1.101要保留2位小数,那么结果有可能是 1.10 和 1.11 ,这个时候两个都是一样近,我们取哪一个呢?规则是保留偶数的那一个,在这里就是保留 1.10。

回到我们之前的就是取m=1.0011001100110011001100110011001100110011001100110100 (52位)

然后我们得到最终的二进制数:

1.0011001100110011001100110011001100110011001100110100 * 2 ^ -2

=0.010011001100110011001100110011001100110011001100110100

转换成十进制就是0.30000000000000004,所以,所以0.1 + 0.2 的最终结果是0.30000000000000004。

BigInt

通过前面的讲解,我们清晰地认识到在以前,JavaScript是没有办法对大于 2^53-1 的数字进行处理的。不过后来,JavaScript提供了内置对象BigInt来处理大数。 BigInt 可以表示任意大的整数。可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如: 10n ,或者调用函数 BigInt() 。

const theBiggestInt = 9007199254740991n;  const alsoHuge = BigInt(9007199254740991); // ↪ 9007199254740991n  const hugeString = BigInt("9007199254740991"); // ↪ 9007199254740991n  typeof 1n === 'bigint'; // true typeof BigInt('1') === 'bigint'; // true  0n === 0 // ↪ false  0n == 0 // ↪ true

用BigInt实现的权限查找代码如下:

hasPermission(permission: Permission) {     const usr_permissions = this.userInfo.usr_permissions     const arr_index = Math.floor(permission / 64)     const bit_index = permission % 64     if (usr_permissions && usr_permissions.length > arr_index) {       if ((BigInt(usr_permissions[arr_index]) >> BigInt(bit_index)) & 1n) {         return true       }     }     return false }

兼容分析

但是BigInt存在兼容性问题:

前端大数的运算及相关知识有哪些

根据我司用户使用浏览器版本数据的分析,得到如下饼状图:

前端大数的运算及相关知识有哪些

不兼容BigInt浏览器的比例占到12.4%

解决兼容性的问题,一种方式是如果希望在项目中继续使用BigInt,那么需要Babel的一些插件进行转换。这些插件需要调用一些方法去检测运算符什么时候被用于BigInt,这将导致不可接受的性能损失,而且在很多情况下是行不通的。另外一种方法就是找一些封装大数运算方法的第三方库,使用它们的语法做大数运算。

用第三方库实现

很多第三方库可以用来做大数运算,大体的思路就是定义一个数据结构来存放大数的正负及数值,分别算出每一位的结果再存储到数据结构中。

jsbn 解决方案

// yarn add jsbn @types/jsbn  import { BigInteger } from 'jsbn'  hasPermission(permission: Permission) {     const usr_permissions = this.userInfo.usr_permissions     const arr_index = Math.floor(permission / 64)     const bit_index = permission % 64     if (usr_permissions && usr_permissions.length > arr_index) {       if (         new BigInteger(usr_permissions[arr_index])           .shiftRight(bit_index)           .and(new BigInteger('1'))           .toString() !== '0'       ) {         return true       }     }     return false   }

jsbi 解决方案

// yarn add jsbi  import JSBI from 'jsbi'  hasPermission(permission: Permission) {     // 开发环境不受权限限制     if (__DEVELOPMENT__) {       return true     }      const usr_permissions = this.userInfo.usr_permissions     const arr_index = Math.floor(permission / 64)     const bit_index = permission % 64     if (usr_permissions && usr_permissions.length > arr_index) {       const a = JSBI.BigInt(usr_permissions[arr_index])       const b = JSBI.BigInt(bit_index)       const c = JSBI.signedRightShift(a, b)       const d = JSBI.BigInt(1)       const e = JSBI.bitwiseAnd(c, d)       if (e.toString() !== '0') {         return true       }     }     return false   }

权限查找新思路

后来,一位同事提到了一种新的权限查找的解决方案:前端获取到数组usr_permission以后,将usr_permission的所有元素转成二进制,并进行字符串拼接,得到一个表示用户所有权限的字符串permissions。当需要查找权限时,查找permissions对应的位数即可。这样相当于在用户进入系统时就将所有的权限都算好,而不是用一次算一次。

在中学时,我们学到的将十进制转成二进制的方法是辗转相除法,这里有一种新思路:

  • 比如我们要用5个二进制位表示11这个数

  • 我们需要先定义一个长度为5,由2的倍数组成的数组[16, 8, 4, 2, 1],然后将11与数组中的元素挨个比较

  • 11 < 16, 所以得到[0, x, x, x, x]

  • 11 >= 8,所以得到[0, 1, x, x, x],11 - 8 = 3

  • 3 < 4,所以得到[0, 1, 0, x, x]

  • 3 >= 2,所以得到[0, 1, 0, 1, x],3 - 2 = 1

  • 1>= 1,所以得到[0, 1, 0, 1, 1],1 - 1 = 0,结束

  • 所以用5位二进制数表示11的结果就是01011

根据上面的思路可以得到的代码如下,这里用big.js这个包去实现:

import Big from 'big.js'         import _ from 'lodash'      permissions = '' // 最后生成的权限字符串      // 生成长度为64,由2的倍数组成的数组     generateBinaryArray(bits: number) {       const arr: any[] = []       _.each(_.range(bits), (index) => {         arr.unshift(Big(2).pow(index))       })       return arr     }        // 将usr_permission中单个元素转成二进制     translatePermission(binaryArray: any[], permission: string) {     let bigPermission = Big(permission)     const permissionBinaryArray: number[] = []     _.each(binaryArray, (v, i) => {       if (bigPermission.gte(binaryArray[i])) {         bigPermission = bigPermission.minus(binaryArray[i])         permissionBinaryArray.unshift(1)       } else {         permissionBinaryArray.unshift(0)       }     })     return permissionBinaryArray.join('')   }      // 将usr_permission中所有元素的二进制形式进行拼接   generatePermissionString() {     const usr_permissions = this.userInfo.usr_permissions     let str = ''     const binaryArray = this.generateBinaryArray(64)     _.each(usr_permissions, (permission, index) => {       str = `${str}${this.translatePermission(binaryArray, permission)}`     })     this.permissions = str   }      // 判断时候拥有某项权限   hasPermission(permission: Permission) {     if (!this.permissions) {       return false     }     return this.permissions[permission] === '1'   }

到此,相信大家对“前端大数的运算及相关知识有哪些”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: 前端大数的运算及相关知识有哪些

本文链接: https://www.lsjlt.com/news/84096.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 前端大数的运算及相关知识有哪些
    本篇内容主要讲解“前端大数的运算及相关知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“前端大数的运算及相关知识有哪些”吧! 背景前段时间我在公...
    99+
    2024-04-02
  • 分享Web前端的相关知识
    这篇文章主要介绍“分享Web前端的相关知识”,在日常操作中,相信很多人在分享Web前端的相关知识问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分享Web前端的相关知识”的疑惑...
    99+
    2024-04-02
  • js函数相关知识点有哪些
    这篇文章将为大家详细讲解有关js函数相关知识点有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在js种函数实际上是对象,每个函数都是Function类型的实例。和其他...
    99+
    2024-04-02
  • 关于JavaScript相关知识有哪些
    这期内容当中小编将会给大家带来有关关于JavaScript相关知识有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。  (一)JS中基本类型和引用类型  JavaScr...
    99+
    2024-04-02
  • Vue loader的相关知识有哪些
    本篇内容介绍了“Vue loader的相关知识有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、处理资源路径当 Vue Loader ...
    99+
    2023-07-05
  • JVM相关的知识点有哪些
    这篇文章主要讲解了“JVM相关的知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JVM相关的知识点有哪些”吧!JVM作为java运行的基础,很难相...
    99+
    2024-04-02
  • synchronized的相关知识点有哪些
    这篇文章主要讲解了“synchronized的相关知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“synchronized的相关知识点有哪些”吧!...
    99+
    2024-04-02
  • 有哪些Java的相关知识点
    这篇文章主要介绍“有哪些Java的相关知识点”,在日常操作中,相信很多人在有哪些Java的相关知识点问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些Java的相关知识点”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-16
  • Git的相关知识点有哪些
    这篇文章主要介绍“Git的相关知识点有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Git的相关知识点有哪些”文章能帮助大家解决问题。分支和合并Git 跟其他版本控制系统***的优势就在于其高级...
    99+
    2023-06-17
  • KeyDB的相关知识点有哪些
    今天小编给大家分享一下KeyDB的相关知识点有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。线程模型KeyDB将redi...
    99+
    2023-06-19
  • Python类的相关知识有哪些
    小编给大家分享一下Python类的相关知识有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、什么是类类(class),作为代码的父亲,可以说它包裹了很多有趣...
    99+
    2023-06-15
  • React的相关知识点有哪些
    这篇文章主要介绍“React的相关知识点有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“React的相关知识点有哪些”文章能帮助大家解决问题。React与传统MVC的关系轻量级的视图层库!A J...
    99+
    2023-06-03
  • HashMap相关知识点有哪些
    本篇内容介绍了“HashMap相关知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!HashMap 和 HashSet 是 Java...
    99+
    2023-06-17
  • Baseline相关知识点有哪些
    本篇内容主要讲解“Baseline相关知识点有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Baseline相关知识点有哪些”吧! 在 Oracle Da...
    99+
    2024-04-02
  • CSS相关知识点有哪些
    本篇内容介绍了“CSS相关知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  1、CSS选择器 ...
    99+
    2024-04-02
  • Java IO相关知识有哪些
    这篇文章主要介绍了Java IO相关知识有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、IO底层是怎么回事?操作系统就是管家,电脑的设备就是资源,如果进程先要操作资源...
    99+
    2023-06-15
  • Spring Cache相关知识有哪些
    这篇文章将为大家详细讲解有关Spring Cache相关知识有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。简介 Spring 从 3.1 开始定义了 org.springframework...
    99+
    2023-06-15
  • MySQL相关知识点有哪些
    这篇文章主要介绍了MySQL相关知识点有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 1、数据库架构1.1...
    99+
    2024-04-02
  • Git相关知识点有哪些
    这篇文章主要讲解了“Git相关知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Git相关知识点有哪些”吧!一、Git工作流程以上包括一些简单而常用...
    99+
    2024-04-02
  • YARN相关知识点有哪些
    本篇内容介绍了“YARN相关知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!YARN产生背景为什么会产生YRAN?这个与MapRe...
    99+
    2023-06-19
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作