轶哥

📚 Having fun with AI Agent. Always learning.

    JavaScript 安全计算
    •   更新:2020-09-17 18:02:17
    •   首发:2020-08-07 19:26:16
    •   教程
    •   4382

    C/C++、Java、JavaScript等语言,都有计算不精准的问题。原因是这些语言在计算的时候遵循IEEE 二进制浮点数算术标准(IEEE 754),跟CPU浮点运算器有关系。

    0.1+0.2!=0.3

    “为什么JS中计算0.1加0.2的时候不等于0.3”,“为什么JS中计算4.44乘以100不等于444”,这类问题在诸多程序员岗位的面试中很常见。各个语言也提供了相应的数学库解决计算精度的问题。

    在涉及大量计算的JavaScript项目中,强烈推荐使用Math.js这个精确计算库解决JS计算不精准的问题。

    Math.js是一个用于JavaScript和Node.js的高级数学计算函数库。它内置大量的函数和常量,具有支持符号计算的表达式解析器,并提供了一个集成的解决方案用于处理不同的数据类型,例如numbers、 big numbers、 complex numbers、 fractions、 units和matrices。强大且易于使用。

    特征

    • 支持数字,大数,复数,分数,单位,字符串,数组和矩阵。
    • 与JavaScript的内置Math库兼容。
    • 包含一个灵活的表达式解析器。
    • 进行符号计算。
    • 带有大量内置函数和常量。
    • 也可以用作命令行应用程序。
    • 在任何JavaScript引擎上运行。
    • 很容易扩展。
    • 开源。

    安装

    
    npm install mathjs
    

    更多内容请直接访问Math.js的开源仓库:https://github.com/josdejong/mathjs

    示例

    常规计算(加减乘除)

    
    import { create, all } from 'mathjs'
    
    
    
    const config = {
    
      number: 'BigNumber',
    
      precision: 64
    
    }
    
    
    
    const math = create(all, config)
    
    
    
    math.evaluate('4.44 * 100')
    
    math.evaluate('0.1 + 0.2')
    

    JS%E7%B2%BE%E5%87%86%E8%AE%A1%E7%AE%97.png

    四舍五入

    在JavaScript中toFixed()方法可把 Number 四舍五入为指定小数位数的数字。

    NumberObject.toFixed(num)
    

    需要注意的是,toFixed()同样存在精度问题。例如2.55取一位小数四舍五入的结果可能是2.5

    toFixed.png

    在JS自带的函数Math.round()中,3.5将舍入为 4,而 -3.5将舍入为-3

    为了避免这类问题,可以通过mathjs提供的round()方法。

    Round

    将值四舍五入到最接近的整数。对于矩阵,该函数按元素进行求值。

    句法

    math.round(x)
    math.round(x, n)
    

    参数

    参数 类型 描述
    x number| BigNumber | Fraction | Complex | Array | Matrix 四舍五入
    n number| BigNumber | Array 小数位数默认值:0。

    返回值

    类型 描述
    number| BigNumber | Fraction | Complex | Array | Matrix 取整值

    例子

    math.round(3.2)              // returns number 3
    math.round(3.8)              // returns number 4
    math.round(-4.2)             // returns number -4
    math.round(-4.7)             // returns number -5
    math.round(math.pi, 3)       // returns number 3.142
    math.round(123.45678, 2)     // returns number 123.46
    
    const c = math.complex(3.2, -2.7)
    math.round(c)                // returns Complex 3 - 3i
    
    math.round([3.2, 3.8, -4.7]) // returns Array [3, 4, -5]
    

    mathjs.png

    math.js更多方法:https://mathjs.org/docs/reference/functions.html

    取整

    在JavaScript中,parseInt()方法可以实现取整。

    parseInt(string, radix)
    

    第二个参数radix可选。表示要解析的数字的基数。

    同样的,通过parseInt()方法取整也存在精度问题。例如:

    parseInt(0.0000001)的结果是1

    parseInt.png

    解决这个问题,只需要确保传入的第一个参数是字符串即可,例如:parseInt('0.0000001', 10),得到的结果就是0了(**注意:parseInt('1e-7')的结果也是1**)。

    第二个参数最好明确指明数字是10进制,否则可能因浏览器遵循的ECMA标准而存在返回值差异。

    当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。

    • 如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。
    • 如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。
    • 如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。

    可这带来一个新的问题,parseInt(0.0000001)产生了隐式转换,得到的结果不是我们想要的。如何将0.0000001正确的转换为'0.0000001'呢?

    对于非负小数取整,我们可以采用Math.floor(0.0000001)方法实现向下取整,避免转换过程。

    如果是负数,那么Math.floor(-0.0000001)将会得到-1,而parseInt('-0.0000001')得到的结果是-0

    因此,对于不超过4294967295(有效整数,int,范围是0-0xffffffff)的数字来说,JavaScript向下取整,可以采用-0.0000001 | 0,或者-0.0000001 >>> 0来实现。

    >>>是无符号位移。所以>>> 0 在JS里面是确保数字有意义的判断方法。

    安全值与最大数

    1.7976931348623157e+308,这个数字究竟意味着什么?

    maxvalue.jpg

    Number.MAX_SAFE_INTEGER 是js里整数的安全的最大值,由于 js 用的是 IEEE 754 双精度浮点,可以安全地表示 [ -2^53+1 , 2^53-1 ] 这个范围。

    Number.MAX_VALUE 属性是 JavaScript 中可表示的最大的数。

    打赏
    交流区

    暂无内容

    尚未登陆
    发布
      上一篇 (PHP 获取客户端真实IP地址)
    下一篇 (路由器当交换机/AP用)  

    评论回复提醒