zoukankan      html  css  js  c++  java
  • 数值

    目录

    概述

    整数和浮点数

    JavaScript内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,11.0是相同的,是同一个数。

    1 === 1.0 // true
    

    这就是说,在JavaScript语言的底层,根本没有整数,所有数字都是小数(64位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时JavaScript会自动把64位浮点数,转成32位整数,然后再进行运算,参见《运算符》一节的”位运算“部分。

    由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。

    0.1 + 0.2 === 0.3
    // false
    
    0.3 / 0.1
    // 2.9999999999999996
    
    (0.3 - 0.2) === (0.2 - 0.1)
    // false
    

    数值精度

    根据国际标准IEEE 754,JavaScript浮点数的64个二进制位,从最左边开始,是这样组成的。

    • 第1位:符号位,0表示正数,1表示负数
    • 第2位到第12位:储存指数部分
    • 第13位到第64位:储存小数部分(即有效数字)

    符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。

    IEEE 754规定,有效数字第一位默认总是1,不保存在64位浮点数之中。也就是说,有效数字总是1.xx...xx的形式,其中xx..xx的部分保存在64位浮点数之中,最长可能为52位。因此,JavaScript提供的有效数字最长为53个二进制位。

    (-1)^符号位 * 1.xx...xx * 2^指数位
    

    上面公式是一个数在JavaScript内部实际的表现形式。

    精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-(253-1)到253-1,都可以精确表示。

    Math.pow(2, 53)
    // 9007199254740992
    
    Math.pow(2, 53) + 1
    // 9007199254740992
    
    Math.pow(2, 53) + 2
    // 9007199254740994
    
    Math.pow(2, 53) + 3
    // 9007199254740996
    
    Math.pow(2, 53) + 4
    // 9007199254740996
    

    从上面示例可以看到,大于2的53次方以后,整数运算的结果开始出现错误。所以,大于等于2的53次方的数值,都无法保持精度。

    Math.pow(2, 53)
    // 9007199254740992
    
    // 多出的三个有效数字,将无法保存
    9007199254740992111
    // 9007199254740992000
    

    上面示例表明,大于2的53次方以后,多出来的有效数字(最后三位的111)都会无法保存,变成0。

    数值范围

    根据标准,64位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是2047(2的11次方减1)。也就是说,64位浮点数的指数部分的值最大为2047,分出一半表示负数,则JavaScript能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。

    如果指数部分等于或超过最大正值1024,JavaScript会返回Infinity(关于Infinity的介绍参见下文),这称为“正向溢出”;如果等于或超过最小负值-1023(即非常接近0),JavaScript会直接把这个数转为0,这称为“负向溢出”。

    var x = 0.5;
    
    for(var i = 0; i < 25; i++) {
      x = x * x;
    }
    
    x // 0
    

    上面代码对0.5连续做25次平方,由于最后结果太接近0,超出了可表示的范围,JavaScript就直接将其转为0。

    至于具体的最大值和最小值,JavaScript提供Number对象的MAX_VALUEMIN_VALUE属性表示(参见《Number对象》一节)。

    Number.MAX_VALUE // 1.7976931348623157e+308
    Number.MIN_VALUE // 5e-324
    

    数值的表示法

    JavaScript的数值有多种表示方法,可以用字面形式直接表示,比如35(十进制)和0xFF(十六进制)。

    数值也可以采用科学计数法表示,下面是几个科学计数法的例子。

    123e3 // 123000
    123e-3 // 0.123
    -3.1E+12
    .1e-23
    

    科学计数法允许字母eE的后面,跟着一个整数,表示这个数值的指数部分。

    以下两种情况,JavaScript会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示。

    (1)小数点前的数字多于21位。

    1234567890123456789012
    // 1.2345678901234568e+21
    
    123456789012345678901
    // 123456789012345680000
    

    (2)小数点后的零多于5个。

    // 小数点后紧跟5个以上的零,
    // 就自动转为科学计数法
    0.0000003 // 3e-7
    
    // 否则,就保持原来的字面形式
    0.000003 // 0.000003
    

    数值的进制

    使用字面量(literal)时,JavaScript对整数提供四种进制的表示方法:十进制、十六进制、八进制、2进制。

    • 十进制:没有前导0的数值。
    • 八进制:有前缀0o0O的数值,或者有前导0、且只用到0-7的七个阿拉伯数字的数值。
    • 十六进制:有前缀0x0X的数值。
    • 二进制:有前缀0b0B的数值。

    默认情况下,JavaScript内部会自动将八进制、十六进制、二进制转为十进制。下面是一些例子。

    0xff // 255
    0o377 // 255
    0b11 // 3
    

    如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错。

    0xzz // 报错
    0o88 // 报错
    0b22 // 报错
    

    上面代码中,十六进制出现了字母z、八进制出现数字8、二进制出现数字2,因此报错。

    通常来说,有前导0的数值会被视为八进制,但是如果前导0后面有数字89,则该数值被视为十进制。

    0888 // 888
    0777 // 511
    

    用前导0表示八进制,处理时很容易造成混乱。ES5的严格模式和ES6,已经废除了这种表示法,但是浏览器目前还支持。

    特殊数值

    JavaScript提供几个特殊的数值。

    正零和负零

    前面说过,JavaScript的64位浮点数之中,有一个二进制位是符号位。这意味着,任何一个数都有一个对应的负值,就连0也不例外。

    在JavaScript内部,实际上存在2个0:一个是+0,一个是-0。它们是等价的。

    -0 === +0 // true
    0 === -0 // true
    0 === +0 // true
    

    几乎所有场合,正零和负零都会被当作正常的0

    +0 // 0
    -0 // 0
    (-0).toString() // '0'
    (+0).toString() // '0'
    

    唯一有区别的场合是,+0-0当作分母,返回的值是不相等的。

    (1 / +0) === (1 / -0) // false
    

    上面代码之所以出现这样结果,是因为除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的(关于Infinity详见后文)。

    NaN

    (1)含义

    NaN是JavaScript的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。

    5 - 'x' // NaN
    

    上面代码运行时,会自动将字符串x转为数值,但是由于x不是数值,所以最后得到结果为NaN,表示它是“非数字”(NaN)。

    另外,一些数学函数的运算结果会出现NaN

    Math.acos(2) // NaN
    Math.log(-1) // NaN
    Math.sqrt(-1) // NaN
    

    0除以0也会得到NaN

    0 / 0 // NaN
    

    需要注意的是,NaN不是一种独立的数据类型,而是一种特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。

    typeof NaN // 'number'
    

    (2)运算规则

    NaN不等于任何值,包括它本身。

    NaN === NaN // false
    

    由于数组的indexOf方法,内部使用的是严格相等运算符,所以该方法对NaN不成立。

    [NaN].indexOf(NaN) // -1
    

    NaN在布尔运算时被当作false

    Boolean(NaN) // false
    

    NaN与任何数(包括它自己)的运算,得到的都是NaN

    NaN + 32 // NaN
    NaN - 32 // NaN
    NaN * 32 // NaN
    NaN / 32 // NaN
    

    (3)判断NaN的方法

    isNaN方法可以用来判断一个值是否为NaN

    isNaN(NaN) // true
    isNaN(123) // false
    

    但是,isNaN只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回true,这一点要特别引起注意。也就是说,isNaNtrue的值,有可能不是NaN,而是一个字符串。

    isNaN('Hello') // true
    // 相当于
    isNaN(Number('Hello')) // true
    

    出于同样的原因,对于对象和数组,isNaN也返回true

    isNaN({}) // true
    // 等同于
    isNaN(Number({})) // true
    
    isNaN(['xzy']) // true
    // 等同于
    isNaN(Number(['xzy'])) // true
    

    但是,对于空数组和只有一个数值成员的数组,isNaN返回false

    isNaN([]) // false
    isNaN([123]) // false
    isNaN(['123']) // false
    

    上面代码之所以返回false,原因是这些数组能被Number函数转成数值,请参见《数据类型转换》一节。

    因此,使用isNaN之前,最好判断一下数据类型。

    function myIsNaN(value) {
      return typeof value === 'number' && isNaN(value);
    }
    

    判断NaN更可靠的方法是,利用NaN是JavaScript之中唯一不等于自身的值这个特点,进行判断。

    function myIsNaN(value) {
      return value !== value;
    }
    

    Infinity

    (1)定义

    Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity

    // 场景一
    Math.pow(2, Math.pow(2, 100))
    // Infinity
    
    // 场景二
    0 / 0 // NaN
    1 / 0 // Infinity
    

    上面代码中,第一个场景是一个表达式的计算结果太大,超出了JavaScript能够表示的范围,因此返回Infinity。第二个场景是0除以0会得到NaN,而非0数值除以0,会返回Infinity

    Infinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。

    Infinity === -Infinity // false
    
    1 / -0 // -Infinity
    -1 / -0 // Infinity
    

    上面代码中,非零正数除以-0,会得到-Infinity,负数除以-0,会得到Infinity

    由于数值正向溢出(overflow)、负向溢出(underflow)和被0除,JavaScript都不报错,而是返回Infinity,所以单纯的数学运算几乎没有可能抛出错误。

    Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。

    Infinity > 1000 // true
    -Infinity < -1000 // true
    

    InfinityNaN比较,总是返回false

    Infinity > NaN // false
    -Infinity > NaN // false
    
    Infinity < NaN // false
    -Infinity < NaN // false
    

    (2)运算规则

    Infinity的四则运算,符合无穷的数学计算规则。

    5 * Infinity // Infinity
    5 - Infinity // -Infinity
    Infinity / 5 // Infinity
    5 / Infinity // 0
    

    0乘以Infinity,返回NaN;0除以Infinity,返回0Infinity除以0,返回Infinity

    0 * Infinity // NaN
    0 / Infinity // 0
    Infinity / 0 // Infinity
    

    Infinitynull计算时,null会转成0,等同于与0的计算。

    null * Infinity // NaN
    null / Infinity // 0
    Infinity / null // Infinity
    

    Infinityundefined计算,返回的都是NaN

    undefined + Infinity // NaN
    undefined - Infinity // NaN
    undefined * Infinity // NaN
    undefined / Infinity // NaN
    Infinity / undefined // NaN
    

    Infinity加上或乘以Infinity,返回的还是Infinity

    Infinity + Infinity // Infinity
    Infinity * Infinity // Infinity
    

    Infinity减去或除以Infinity,得到NaN

    Infinity - Infinity // NaN
    Infinity / Infinity // NaN
    

    (3)isFinite函数

    isFinite函数返回一个布尔值,检查某个值是不是正常数值,而不是Infinity

    isFinite(Infinity) // false
    isFinite(-1) // true
    isFinite(true) // true
    isFinite(NaN) // false
    

    上面代码表示,如果对NaN使用isFinite函数,也返回false,表示NaN不是一个正常值。

    与数值相关的全局方法

    parseInt()

    (1)基本用法

    parseInt方法用于将字符串转为整数。

    parseInt('123') // 123
    

    如果字符串头部有空格,空格会被自动去除。

    parseInt('   81') // 81
    

    如果parseInt的参数不是字符串,则会先转为字符串再转换。

    parseInt(1.23) // 1
    // 等同于
    parseInt('1.23') // 1
    

    字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。

    parseInt('8a') // 8
    parseInt('12**') // 12
    parseInt('12.34') // 12
    parseInt('15e2') // 15
    parseInt('15px') // 15
    

    上面代码中,parseInt的参数都是字符串,结果只返回字符串头部可以转为数字的部分。

    如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN

    parseInt('abc') // NaN
    parseInt('.3') // NaN
    parseInt('') // NaN
    parseInt('+') // NaN
    parseInt('+1') // 1
    

    parseInt的返回值只有两种可能,不是一个十进制整数,就是NaN

    如果字符串以0x0X开头,parseInt会将其按照十六进制数解析。

    parseInt('0x10') // 16
    

    如果字符串以0开头,将其按照10进制解析。

    parseInt('011') // 11
    

    对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。

    parseInt(1000000000000000000000.5) // 1
    // 等同于
    parseInt('1e+21') // 1
    
    parseInt(0.0000008) // 8
    // 等同于
    parseInt('8e-7') // 8
    

    (2)进制转换

    parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数。默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。

    parseInt('1000') // 1000
    // 等同于
    parseInt('1000', 10) // 1000
    

    下面是转换指定进制的数的例子。

    parseInt('1000', 2) // 8
    parseInt('1000', 6) // 216
    parseInt('1000', 8) // 512
    

    上面代码中,二进制、六进制、八进制的1000,分别等于十进制的8、216和512。这意味着,可以用parseInt方法进行进制的转换。

    如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN。如果第二个参数是0undefinednull,则直接忽略。

    parseInt('10', 37) // NaN
    parseInt('10', 1) // NaN
    parseInt('10', 0) // 10
    parseInt('10', null) // 10
    parseInt('10', undefined) // 10
    

    如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回NaN

    parseInt('1546', 2) // 1
    parseInt('546', 2) // NaN
    

    上面代码中,对于二进制来说,1是有意义的字符,546都是无意义的字符,所以第一行返回1,第二行返回NaN

    前面说过,如果parseInt的第一个参数不是字符串,会被先转为字符串。这会导致一些令人意外的结果。

    parseInt(0x11, 36) // 43
    // 等同于
    parseInt(String(0x11), 36)
    parseInt('17', 36)
    

    上面代码中,十六进制的0x11会被先转为十进制的17,再转为字符串。然后,再用36进制解读字符串17,最后返回结果43

    这种处理方式,对于八进制的前缀0,尤其需要注意。

    parseInt(011, 2) // NaN
    // 等同于
    parseInt(String(011), 2)
    
    parseInt('011', 2) // 3
    

    上面代码中,第一行的011会被先转为字符串9,因为9不是二进制的有效字符,所以返回NaN。第二行的字符串011,会被当作二进制处理,返回3。

    ES5不再允许将带有前缀0的数字视为八进制数,而是要求忽略这个0。但是,为了保证兼容性,大部分浏览器并没有部署这一条规定。

    parseFloat()

    parseFloat方法用于将一个字符串转为浮点数。

    parseFloat('3.14') // 3.14
    

    如果字符串符合科学计数法,则会进行相应的转换。

    parseFloat('314e-2') // 3.14
    parseFloat('0.0314E+2') // 3.14
    

    如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。

    parseFloat('3.14more non-digit characters') // 3.14
    

    parseFloat方法会自动过滤字符串前导的空格。

    parseFloat('	v
    12.34
     ') // 12.34
    

    如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN

    parseFloat([]) // NaN
    parseFloat('FF2') // NaN
    parseFloat('') // NaN
    

    上面代码中,尤其值得注意,parseFloat会将空字符串转为NaN

    这些特点使得parseFloat的转换结果不同于Number函数。

    parseFloat(true)  // NaN
    Number(true) // 1
    
    parseFloat(null) // NaN
    Number(null) // 0
    
    parseFloat('') // NaN
    Number('') // 0
    
    parseFloat('123.45#') // 123.45
    Number('123.45#') // NaN
    

    参考链接

    from: http://javascript.ruanyifeng.com/grammar/number.html

  • 相关阅读:
    14.4.9 Configuring Spin Lock Polling 配置Spin lock 轮询:
    14.4.8 Configuring the InnoDB Master Thread IO Rate 配置InnoDB Master Thread I/O Rate
    14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量
    14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量
    14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发
    14.4.6 Configuring Thread Concurrency for InnoDB 配置Thread 并发
    14.4.5 Configuring InnoDB Change Buffering 配置InnoDB Change Buffering
    14.4.5 Configuring InnoDB Change Buffering 配置InnoDB Change Buffering
    14.4.4 Configuring the Memory Allocator for InnoDB InnoDB 配置内存分配器
    14.4.4 Configuring the Memory Allocator for InnoDB InnoDB 配置内存分配器
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/5831671.html
Copyright © 2011-2022 走看看