美文网首页
刷算法题遇到的新数据类型-—-BigInt

刷算法题遇到的新数据类型-—-BigInt

作者: dingFY | 来源:发表于2020-09-30 17:50 被阅读0次

    今天在LeetCode做的一道关于 “加一” 的算法题,题目如下

    `给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
    最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
    你可以假设除了整数 0 之外,这个整数不会以零开头。

    示例 1:
    输入: [1,2,3]
    输出: [1,2,4]
    解释: 输入数组表示数字 123。

    示例 2:
    输入: [4,3,2,1]
    输出: [4,3,2,2]
    解释: 输入数组表示数字 4321。`

    我的代码是这样的

    const plusOne = function(digits) {
        for(let i = digits.length - 1;i >= 0;i--){
            if(digits[i] == 9){
                digits[i] = 0;
            } else {
                digits[i]++;
                return digits;
            }
        }
        // 为9的情况
        digits.unshift(1);
        return digits;
    };
    

    后面在题解区看到一位大神的代码只有一行

    const plusOne = (digits) => {
      return (BigInt(digits.join('')) + 1n).toString().split('');
    };
    
    

    这个方法很巧妙,将数组转换成字符串,再转换成数字进行加一计算,最后再转回数组。我们平时将字符串强制转成数字用的是Number(), 这里的BigInt是什么呢?接下来我们详细了解下BigInt。

    一、Number 类型的局限性

    JavaScript 内部只有一种数字类型Number,也就是说,JavaScript 语言的底层根本没有整数,所有数字都是以IEEE-754标准格式64位浮点数形式储存,1与1.0是相同的。因为有些小数以二进制表示位数是无穷的。JavaScript会把超出53位之后的二进制舍弃,所以涉及小数的比较和运算要特别小心。 具体介绍可查看我的另外一篇文章:解决JS浮点数运算结果不精确的Bug

    这意味着在JavaScript中,Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能被自动四舍五入丢失精度。如下,可以看到 max + 1 与 max + 2 的值相同,这显然是不对的。

    let max = Number.MAX_SAFE_INTEGER
    console.log(max) // 9007199254740991
    console.log(max + 1) // 9007199254740992
    console.log(max + 2) // 9007199254740992
    

    二、解决方案

    在没有 BigInt 的时候,如果想要使用大整型,一些JS开发人员使用字符串类型表示大整数。 例如,Twitter API 在使用 JSON 进行响应时会向对象添加字符串版本的 ID。 还可以借助类似 BigInt 功能的第三方库。例如 bignumber.js。这有可能会影响 JavaScript 程序的效率,比如加载时间、解析时间、编译时间,以及运行时的效率。

    三、BigInt介绍

    BigInt数据类型的目的是比Number数据类型支持的范围更大的整数值。在对大整数执行数学运算时,以任意精度表示整数的能力尤为重要。使用BigInt,整数溢出将不再是问题。

    四、定义BigInt

    【4.1】在整数的末尾追加n

    // 十进制
    console.log(10n);      // 10n   
    
    // 二进制
    console.log(0b10n);    // 2n    
    console.log(0B10n);    // 2n
    
    // 八进制
    console.log(0o5n);     // 5n    
    console.log(0O5n);     // 5n
    
    // 十六进制
    console.log(0xFn);     // 15n   
    console.log(0XFn);     // 15n
    

    【4.2】调用 BigInt() 构造函数

    // 十进制
    console.log(BigInt('10');      // 10n   
    
    // 二进制
    console.log(BigInt('0b10'));    // 2n   
    console.log(BigInt('0B10'));    // 2n
    
    // 八进制
    console.log(BigInt('0o5'));     // 5n   
    console.log(BigInt('0O5'));     // 5n
    
    // 十六进制
    console.log(BigInt('0xF'));     // 15n  
    console.log(BigInt('0XF'));     // 15n
    

    五、BigInt类型

    既然 BigInt 是一个新的原始类型,那么它就可以使用 typeof 检测出自己的类。请记住,不能使用严格相等运算符将 BigInt 与常规数字进行比较,因为它们的类型不同:

    typeof(10)  // number
    typeof(10n) // bigint
    
    10n === 10  // false
    10n == 10   // true
    

    六、BigInt运算

    BigInt 支持绝大部分常用运算符:+,-,,/,%,*。 除 >>>(无符号右移)之外的位运算符也可以支持:|,&,<<,>>,^,因为BigInt都是有符号的。为了兼容 asm.js ,BigInt不支持单目 (+) 运算符。另外就是不能混合使用 BigInt与 Number 计算,否则会抛出异常

    10n + 20n;    // 30n    
    10n - 20n;    // -10n   
    +10n;         // TypeError: Cannot convert a BigInt value to a number   
    -10n;         // -10n   
    10n * 20n;    // 200n   
    20n / 10n;    // 2n 
    23n % 10n;    // 3n 
    10n ** 3n;    // 1000n  
    const x = 10n;  
    ++x;          // 11n    
    --x;          // 9n
    10n + 10;     // TypeError: Cannot mix BigInt and other types
    
    // 混合运算需转换
    BigInt(10) + 10n; // 20n
    Number(10 ) + 10; // 20
    

    七、BigInt与Number的比较

    【7.1】BigInt只是函数,没有构造器,因此不能使用 new 来创建 BigInt 的实例

    new Number(1) // √
    new BigInt(1) // ×
    

    【7.2】****当没有参数时,Number返回0,BigInt抛出TypeError

    Number() // 0
    BigInt() // TypeError
    

    【7.3】当参数为非数字时,Number返回NaN,BigInt抛出TypeError或SyntaxError

    Number(undefined) // NaN
    BigInt(undefined) // TypeError
    
    Number(null) // 0
    BigInt(null) // TypeError
    
    Number({}) // NaN
    BigInt({}) // SyntaxError
    
    Number("foo")  // NaN
    BigInt("foo") // SyntaxError
    

    【7.4】两者对 -0 的处理也不同

    Number(-0) === -0
    BigInt(-0) === -0n
    

    【7.4】对于布尔值,两者都会把 true 转换为 1,把 false 转换为 0

    Number(true)  // 1
    Number(false) // 0
    
    BigInt(true)  // 1n
    BigInt(false) // 0n
    

    【7.5】对于浮点数,BigInt抛出 RangeError 异常

    BigInt(4.00000001) // RangeError
    

    【7.6】****对于 NaN 和正负无穷,BigInt抛出RangeError异常

    BigInt(NaN)       // RangeError
    BigInt(-Infinity) // RangeError
    BigInt(+Infinity) // RangeError
    

    7.7当使用 BigInt 时,带小数的运算会被取整

    let a = 5 / 2;    // 2.5
    let b = 5n / 2n;  // 2n
    

    【7.8】Number 和 BigInt 可以进行比较,两者也可以混在一个数组内并排序。

    1n < 2   // true
    2n > 1   // true
    2n > 2   // false
    2n >= 2  // true
    
    let arr = [3n, 4, 2, 1n, 0, -1n]
    arr.sort() // [-1n, 0, 1n, 2, 3n, 4]
    

    八、实例方法

    【8.1】BigInt.prototype.toLocaleString() : **返回此数字的 language-sensitive 形式的字符串 查看案例

    【8.2】BigInt.prototype.toString() : **返回以指定基数(base)表示指定数字的字符串 查看案例

    【8.3】BigInt.prototype.valueOf(): **返回指定对象的基元值 查看案例

    九、注意

    1、由于在 Number 与 BigInt 之间进行转换会损失精度,因而建议仅在值可能大于2^53 时使用 BigInt 类型,并且不在两种类型之间进行相互转换。

    2、对任何 BigInt 值使用 JSON.stringify() 都会引发 TypeError,因为默认情况下 BigInt 值不会在 JSON 中序列化。

    3、如果你确定你的页面只跑在最新的 Chrome 中,那么现在就可以大胆的使用 BigInt 了,更优雅高效的处理大数据。若在其他浏览器中需要支持,可以使用 JSBI 这个库,日后甩掉它的姿势也十分优雅

    文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料

    相关文章

      网友评论

          本文标题:刷算法题遇到的新数据类型-—-BigInt

          本文链接:https://www.haomeiwen.com/subject/uyfrnhtx.html