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úmero0-9
, no se utiliza ningún prefijo. - Binario (Binario):
El valor es digital0
y1
; el prefijo0b
es o0B
. - Hexadecimal (Hexadecimal):
dígitos del valor0-9
ya-f
; prefijo0x
o0X
. - Octal:
número de valor0-7
; prefijo0o
o0O
(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-9
una 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 inversa1011
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.001
0.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.8
etc.
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.
-
parseInt
Parte entera: use la función directamente aquíparseInt('1011', 2) => 11
,. -
Parte decimal: como
1011.001
el lugar decimal001
, 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.125El 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
}