Múltiples bases y conversiones de bases en JavaScript

Introducción

JavaScript Hay cuatro métodos de representación proporcionados en: decimal, binario, hexadecimal y octal.
Para los literales numéricos, se utilizan principalmente diferentes prefijos para distinguir:

  • Decimal (Decimal):
    El valor es un número  0-9, no se utiliza ningún prefijo.
  • Binario (Binario):
    El valor es digital  0 y  1 ; el prefijo  0b es o  0B.
  • Hexadecimal (Hexadecimal):
    dígitos del valor  0-9 y  a-f ; prefijo  0x o  0X.
  • Octal:
    número de valor  0-7 ; prefijo  0o o  0O (regulación ES6).

Cabe señalar que el navegador admite el modo no estricto: si hay un prefijo 0 y solo se  0-7 utilizan ocho dígitos detrás de él, el valor se considera octal; pero si hay 8 o 9 en los dígitos que siguen al prefijo 0, luego se trata como decimal.
En modo estricto, si el número tiene el prefijo 0, se informará un error: Error de sintaxis no detectado: los decimales con ceros a la izquierda no están permitidos en modo estricto.
Valores en varias bases, si el valor excede el rango dado, se informará un error: Error de sintaxis no detectado: token no válido o inesperado.

De forma predeterminada, dentro de JavaScript, los valores literales binarios, hexadecimales y octales se convierten automáticamente a decimal para su cálculo.

0x22 // 34
0b111 // 7
0o33 // 27
0x22 + 0b111 // 41
0o33 + 12 // 39
(0x33).toString() // 51
(0x33).valueOf() // 51

Excepto que decimal es la base numérica predeterminada en Javascript, las otras tres bases rara vez se usan, principalmente cuando se trata de datos subyacentes, codificación de bytes u operaciones de bits.

Conversión

Este artículo discutirá principalmente los problemas en la conversión de bases.
JavaScript proporciona funciones nativas para convertir entre decimales y otras bases.
Entre ellas, hay tres formas de convertir de otras bases a decimal: parseInt(), Number(), +(operador unario). Los tres métodos sólo pueden convertir números enteros.
Se puede utilizar la conversión de decimal a otras bases  Number.prototype.toString(). Se admiten decimales.

parseInt(cadena, base)

El primer parámetro es la cadena que se va a analizar; otras bases no tienen prefijos.
El segundo parámetro es un número base, que indica qué sistema base se utiliza para comprender la cadena durante la conversión. El valor predeterminado es 10, lo que significa convertir a decimal.
Si el segundo parámetro no es un número, se convertirá automáticamente en un número. Si no se puede convertir en un número, este parámetro se ignorará; si es un número, debe ser un número entero. Si excede este  2-36 rango , será devuelto  NaN.

parseInt('1111', 2) // 15
parseInt('1234', 8) // 668
parseInt('18af', 16) // 6319
parseInt('1111') // 1111

Si no se pasa el segundo parámetro, la cadena parseInt se  analizará en decimal de forma predeterminada; sin embargo, si la cadena 0x comienza con , se considerará un número hexadecimal.
Y las cadenas de caracteres en otras bases, 0o21(八进制)no 0b11(二进制) se convertirán automáticamente con la base de la base, sino que se obtendrán  0.
Por lo tanto, cuando se utiliza  parseInt la conversión binaria, para garantizar la exactitud y estabilidad de los resultados de la ejecución, no se puede omitir el segundo parámetro .

parseInt('0x21') // 33
parseInt('0o21') // 0
parseInt('0b11') // 0
parseInt('111', 'add') // 111
parseInt('111', '787') // NaN

Si hay caracteres que no son válidos para la base actual en la cadena que se va a analizar, el carácter válido se convertirá desde el bit más alto y se devolverá NaN si no hay ningún carácter válido.

parseInt('88kk', 16) // 136,=== 0x88
parseInt('kk', 16) // NaN

Número()

Puede convertir cadenas en números, admitir cadenas en otras bases y convertir a números decimales de forma predeterminada.
Devuelve si hay un carácter base no válido en la cadena  NaN.
Recuerde, debe utilizar el prefijo base, 0b, 0o, 0x.

Number('0b11100') // 28
Number('0o33') // 27
Number('0x33') //51

Number('0x88kk') // NaN

+ (operador unario)

Al igual que  Number() con , puede convertir cadenas en números, admitir cadenas en otras bases y convertir a números decimales de forma predeterminada.
Devuelve si hay un carácter base no válido en la cadena  NaN.
También se requiere un prefijo base.

+'0b11100' // 28
+'0o33' // 27
+'0x33' //51

+'0x88kk' // NaN

Se puede ver que lo básico y  Number() es lo mismo, ambos son esencialmente un proceso de conversión de números.

Número.prototipo.toString(base)

Admite pasar una base, que se utiliza para convertir el número en una cadena correspondiente a la base, y admite la conversión de decimales .
No se especifica el valor predeterminado  10, el rango del parámetro base  2-36, si excede el rango, se informará un error: RangeError.

15..toString(2) // 1111
585..toString(8) // 1111
4369..toString(16) // 1111
(11.25).toString(2) // 1011.01

conversión personalizada

Además de estas funciones nativas, usted mismo también puede implementar funciones de conversión entre números base.
Según las reglas correspondientes, se pueden realizar algunos métodos de conversión entre decimal, binario y hexadecimal.

Conversión de decimal a hexadecimal

El siguiente código es para la conversión de números enteros entre decimal y hexadecimal, y la conversión se realiza de acuerdo con las reglas básicas.
Hexadecimal es  0-9una a-f forma de describir números, donde  0-9 se toma el valor del número en sí y  a-f se toma  10-15 el valor del número .
Y las letras no distinguen entre mayúsculas y minúsculas.

function int2Hex (num = 0) {
  if (num === 0) {
    return '0'
  }
  const HEXS = '0123456789abcdef'
  let hex
  while (num) {
    hex = HEXS.charAt(num % 16) + hex
    num = Math.floor(num / 16)
  }
  return hex
}
function hex2Int (hex = '') {
  if (typeof hex !== 'string' || hex === '') {
    return NaN
  }
  const hexs = [...hex.toLowerCase()]
  let resInt = 0
  for (let i = 0; i < hexs.length; i++) {
    const hv = hexs[i]
    let num = hv.charCodeAt() < 58 ? +hv : ((code - 97) + 10)
    resInt = resInt * 16 + num
  }
  return resInt
}

Si desea convertir octal, en realidad es muy similar al hexadecimal, solo necesita realizar algunos cambios de acuerdo con el rango de valores de octal. Octal generalmente se usa muy poco y no se enumera por separado.

Lo siguiente se centrará en los conocimientos relevantes de la conversión binaria, incluida la representación binaria y la conversión de decimales.

Conversión decimal y binaria

En Conversión de decimal a binario consideraremos los decimales para comprender cómo se convierten los decimales entre los dos.
Primero seleccione un número, como por ejemplo:, 11.125 veamos la representación del número en binario:

(11.125).toString(2) // 1011.001

Se puede observar que 11.125 la representación binaria de es: 1011.001. A continuación se tomará este número como ejemplo para realizar la operación de conversión.

convertir un número decimal a binario

Lo primero que hay que entender es cómo se deriva el método de representación decimal binaria:

  • La  parte entera se puede calcular así en representación binaria, el número 11:
    11 / 2 ——— 1
    5/2 ——— 1
    2 / 2 ——— 0
    1 / 2 ———— 1
    La regla del número entero parte, el resultado es  从下往上que la fila inversa  1011 es 11 en binario.

  • Los decimales  se pueden calcular en binario, decimales  0.125:
    por ejemplo, decimal 0,125
    0,125 × 2 = 0,25 ——— 0
    0,25 × 2 = 0,5 ——— 0
    0,5 × 2 = 1 ———— 1
    solo termina cuando es igual a 1 , si el resultado no es igual a 1, el ciclo continuará para siempre.
    Según las reglas de la parte fraccionaria, el resultado es que   es binario  从上往下a lo largo de la fila  .0.0010.125

    Entero + decimal, entonces  11.125 la representación binaria: 1011.001.
    De acuerdo con las reglas anteriores para el cálculo separado de números enteros y decimales, la función de convertir decimal a binario se puede obtener de la siguiente manera:

    function c10to2 (num) {
      // 整数
      const numInteger = Math.floor(num)
      // 小数
      const numDecimal = num - numInteger
    
      let integers = []
      if (numInteger === 0) {
        integers = ['0']
      } else {
        let integerVal = numInteger
        while(integerVal !== 1) {
          integers.push(integerVal % 2 === 0 ? '0' : '1')
          integerVal = Math.floor(integerVal / 2)
        }
        integers.push('1')
      }
      const resInteger = integers.reverse().join('')
    
      let decimals = []
      if (numDecimal) {
        let decimalVal = numDecimal
        // 最多取49位的长度
        let count = 49
        while (decimalVal !== 1 && count > 0) {
          decimalVal = decimalVal * 2
          if (decimalVal >= 1) {
            decimals.push('1')
            if (decimalVal > 1) {
              decimalVal = decimalVal - 1
            }
          } else {
            decimals.push('0')
          }
          count--
        }
      }
      const resDecimal = decimals.join('')
    
      return resInteger + (resDecimal ? ('.' + resDecimal) : '')
    }
    

    Cuando los decimales se convierten a binarios, habrá un problema de bucle infinito. El código anterior intercepta los primeros 49 valores.
    Por lo tanto, aquí surge una pregunta, cuál es un problema común de precisión digital: 0.1 + 0.2 != 0.3.

0,1+ 0,2 != 0,3

Solo mire  0.1 la conversión a binario:
0,1 × 2 = 0,2
0,2 ​​× 2 = 0,4
0,4 ​​× 2 = 0,8
0,8 × 2 = 1,6
0,6 × 2 = 1,2
0,2 ​​× 2 = 0,4 // el ciclo comienza
0,4 × 2 = 0,8
0,8 × 2 = 1,6
0,6 × 2 = 1,2
...
...
bucle infinito

0.2 Convertir a binario:
0,2 × 2 = 0,4
0,4 ​​×
2 = 0,8 0,8 ×
2 = 1,6 0,6 × 2 = 1,2 0,2
​​× 2 = 0,4 // el bucle comienza
0,4 × 2 = 0,8
0,8 × 2 = 1,6
0,6 × 2 = 1,2
.. ...
bucle
infinito

Debido a que no se puede obtener 1, se puede encontrar que el decimal finito  0.1 se convierte en un decimal binario infinito  0.00011001100...y 0.2 se convierte  0.001100110011....
Debido al bucle infinito, la precisión inevitablemente se perderá, sucede que  0.1 + 0.2 el último dígito del número calculado después de la pérdida de precisión no es 0, por lo que el resultado es: 0.30000000000000004.
Si el último dígito después de truncar la precisión es 0, entonces, naturalmente, no habrá resultados desiguales. Por ejemplo  0.1 + 0.6 === 0.7, de hecho, 0.1 y 0.6 perderán precisión después de convertirse a binario, pero los valores truncados son todos 0, por lo que son igual.
También los hay desiguales,  0.1 + 0.7 !== 0.8etc.
Por lo tanto, se debe a la pérdida de precisión al convertir a binario durante el cálculo  0.1 + 0.2 !== 0.3.

Todos los valores en JavaScript se almacenan como números de punto flotante de doble precisión de 64 bits estándar IEEE-754.
La parte fraccionaria del número de punto flotante de doble precisión de 64 bits estándar IEEE 754 admite hasta 53 dígitos binarios.
Debido a la limitación de los lugares decimales de los números de punto flotante, los números binarios deben truncarse primero y luego convertirse a decimal, por lo que se producirán errores al realizar cálculos aritméticos.

Se puede ver aquí que si el decimal se va a convertir en un decimal binario finito, entonces el primer dígito del decimal calculado debe estar al  5 final (porque solo  0.5 × 2 el decimal se puede convertir en un número entero).

convertir un número binario a decimal

El método es: dividir el binario en partes enteras y decimales, convertirlas por separado y luego combinarlas en el valor decimal del resultado.

  1. parseInt Parte entera: use la función directamente aquí  parseInt('1011', 2) => 11,.

  2. Parte decimal: como  1011.001 el lugar decimal  001, utilice el método de cálculo de la siguiente tabla.
    Parte fraccionaria|0|0|1
    --|--|--|--la
    potencia del dígito de la base|2-1|2-2|2^-3
    el producto de cada bit y la base|0 × ( 2^- 1)|0 × (2-2)|1×(2-3)
    resultado del producto por bit|0|0|0.125

    El resultado final es la suma de los resultados del producto por bit: 0+0+0.125 = 0.125.

Los números enteros y decimales se combinan para obtener  1011.001 el número decimal: 11.125.

Según las reglas, la implementación del código es la siguiente:

function c2To10 (binaryStr = '') {
  if (typeof binaryStr !== 'string' || binaryStr === '') {
    return NaN
  }
  const [ binIntStr, binDecStr ] = binaryStr.split('.')
  let binDecimal = 0
  if (binDecStr) {
    binDecimal = [...binDecStr].reduce((res, val, index) => {
      res += Number(val) * (2 ** (-(index + 1)))
      return res
    }, 0)
  }
  return parseInt(binIntStr, 2) + binDecimal
}

Supongo que te gusta

Origin blog.csdn.net/jh035/article/details/128128178
Recomendado
Clasificación