Bases numéricas, tamaños en bytes y las unidades sobre las que se discute
Un número escrito lleva dos cosas: un valor y un conjunto de suposiciones sobre cómo hay que leerlo. 0xFF, 255, 0o377 y 11111111 son una misma cantidad en cuatro notaciones. Un terabyte y un tebibyte se diferencian en un diez por ciento. 1,234 es más o menos mil en Londres y más o menos uno en Berlín. La mayoría de los fallos numéricos vienen de las suposiciones, no de la aritmética.
Binario, octal, decimal y hexadecimal
Todas las bases posicionales funcionan igual. Cada posición vale la base multiplicada por la posición que tiene a su derecha, y los dígitos van de cero a la base menos uno. La base 16 necesita seis dígitos adicionales, así que toma prestadas las letras de la A a la F para los valores del diez al quince.
El hexadecimal se usa para bytes y colores porque 16 es 2 elevado a 4, así que un dígito hexadecimal son exactamente cuatro bits y un byte son exactamente dos dígitos hexadecimales, sin acarreo entre ellos.
0 0000 4 0100 8 1000 C 1100
1 0001 5 0101 9 1001 D 1101
2 0010 6 0110 A 1010 E 1110
3 0011 7 0111 B 1011 F 1111
Esa tabla es toda la conversión. Para pasar de hexadecimal a binario, sustituye cada dígito por sus cuatro bits: 0x2F se convierte en 0010 1111. Para volver, agrupa los bits de cuatro en cuatro desde la derecha, rellenando la izquierda con ceros, y lee cada grupo en la tabla.
Para el decimal, usa los valores posicionales. 0x2F es 2 x 16 + 15, o sea 47. En el otro sentido, divide entre 16 repetidamente y lee los restos de abajo arriba:
200 / 16 = 12 remainder 8 -> 8
12 / 16 = 0 remainder 12 -> C
200 decimal = 0xC8
El octal empaqueta tres bits por dígito, y por eso los permisos de Unix se escriben como 755: cada dígito es un trío rwx, siendo 7 igual a 111 y 5 igual a 101. Un color de CSS como #FF8800 son tres bytes, uno por canal, cada uno de 0 a 255, y la forma abreviada de tres dígitos #F80 se expande duplicando cada dígito, no rellenando con ceros. El conversor de bases numéricas cubre las cuatro bases a la vez.
El complemento a dos y de dónde salen los rangos
Un byte contiene 256 patrones distintos. Leídos como sin signo, van de 0 a 255. Leídos como con signo, el bit más alto marca la mitad negativa, y un valor negativo es su patrón menos 256. Ese esquema es el complemento a dos, elegido porque así la suma binaria normal funciona igual con valores con signo y sin signo.
Para negar un número, invierte todos los bits y suma uno. El rango es asimétrico porque el cero ocupa uno de los 128 huecos de la mitad no negativa, así que un byte con signo va de -128 a 127. Sumar uno al extremo superior del rango da la vuelta hasta el extremo inferior:
0111 1111 127
+ 0000 0001 1
= 1000 0000 -128
En la mayoría de lenguajes no se avisa de nada; el valor simplemente aparece al otro lado del rango. Esa misma vuelta con 32 bits es el problema de 2038, en el que una marca de tiempo Unix de 32 bits con signo se agota a los 2.147.483.647 segundos. Con 16 bits sin signo se obtiene de 0 a 65.535, que es exactamente por lo que los números de puerto TCP se detienen ahí, y por lo que el generador de puertos aleatorios elige dentro de ese rango evitando los puertos reservados por debajo de 1024.
Kilobytes, kibibytes y los gigabytes que faltan
Los fabricantes de almacenamiento cuentan en potencias de diez. Los sistemas operativos han contado históricamente en potencias de dos y han etiquetado el resultado con el prefijo decimal, que es donde empieza la discusión. Los prefijos binarios (KiB, MiB, GiB) existen para eliminar la ambigüedad.
| Potencia de diez | Valor decimal | Prefijo binario | Valor binario | Diferencia |
|---|---|---|---|---|
| kB, 10^3 | 1.000 | KiB, 2^10 | 1.024 | 2,4% |
| MB, 10^6 | 1.000.000 | MiB, 2^20 | 1.048.576 | 4,9% |
| GB, 10^9 | 1.000.000.000 | GiB, 2^30 | 1.073.741.824 | 7,4% |
| TB, 10^12 | 1.000.000.000.000 | TiB, 2^40 | 1.099.511.627.776 | 10,0% |
| PB, 10^15 | 10^15 | PiB, 2^50 | 1.125.899.906.842.624 | 12,6% |
Un disco de 1 TB contiene 10^12 bytes tal como se vende. Divide eso entre 2^30 y obtienes 931,32, así que Windows informa de unos 931 GB usando la etiqueta decimal para una cantidad binaria. No falta nada; los mismos bytes se están dividiendo entre otro número. macOS y la mayoría de herramientas de Linux informan ahora en GB decimales, que coinciden con la caja. Los tamaños de memoria sí son binarios de verdad, así que 16 GB de RAM son realmente 16 GiB.
Las velocidades de red se cuentan en bits, no en bytes, y siempre en decimal. Una línea de 100 Mbps transporta 100.000.000 de bits por segundo, que son 12,5 MB por segundo antes de la sobrecarga. La sobrecarga del protocolo se lleva un pequeño porcentaje, así que de 11 a 12 MB por segundo es el techo realista. Dividir entre ocho una cifra anunciada en megabits es la comprobación rápida, y el conversor de unidades cubre las unidades de almacenamiento.
La coma flotante y por qué el dinero no es un float
Las fracciones binarias solo pueden representar sumas de mitades, cuartos, octavos y así sucesivamente. Un décimo no tiene forma binaria exacta, igual que un tercio no tiene forma decimal exacta, así que 0.1 almacenado como un doble IEEE 754 es un poco más de un décimo. Suma dos aproximaciones así y el error sale a la superficie:
0.1 + 0.2 = 0.30000000000000004
Un doble tiene 53 bits de mantisa. Eso hace que todos los enteros hasta 2^53 (9.007.199.254.740.992) sean exactamente representables, junto con cualquier fracción cuyo denominador sea una potencia de dos. Por encima de 2^53 la distancia entre valores representables pasa a ser 2, así que 2^53 + 1 es igual a 2^53. Por eso los identificadores de base de datos de 64 bits que se envían por JSON deberían viajar como cadenas: los números de JavaScript son dobles, y un identificador de 19 dígitos pierde sin avisar sus últimos dígitos.
Para el dinero, guarda unidades menores enteras (céntimos) o usa un tipo decimal que trabaje en base diez. No compares nunca números en coma flotante por igualdad; compara la diferencia contra una tolerancia pequeña. La calculadora de expresiones también trabaja con dobles y hereda los mismos límites.
Redondear, y redondear dos veces
El redondeo al alza en el empate (half up) aleja el valor del cero. El redondeo al par (half even), también llamado redondeo bancario, lleva el empate al dígito par más cercano, lo que elimina el sesgo al alza que introduce el primero a lo largo de una columna larga de cifras. Es el comportamiento por defecto de IEEE 754 y la regla en varias normas contables.
| Valor | Al alza | Al par |
|---|---|---|
| 0,5 | 1 | 0 |
| 1,5 | 2 | 2 |
| 2,5 | 3 | 2 |
| 3,5 | 4 | 4 |
| -0,5 | -1 | 0 |
Redondea una sola vez, a partir del valor original. Redondear 2,4449 a tres decimales da 2,445, y redondear eso a dos da 2,45, mientras que redondear el original directamente a dos da 2,44. El redondeo encadenado a través de columnas intermedias es una fuente habitual de totales que se desvían un céntimo. Una sorpresa relacionada: 2,675 se redondea a 2,67 en la mayoría de lenguajes, porque el doble almacenado es 2,67499999999999982.
Porcentaje y punto porcentual
Una tasa que pasa del 4% al 5% ha subido un punto porcentual, o un 25% en términos relativos. Las dos cifras son correctas, y hay que decir cuál es la unidad.
Las variaciones porcentuales no se cancelan. Una caída del 50% seguida de una subida del 50% deja 75, no 100, porque el segundo porcentaje se toma sobre una base más pequeña. Recuperarse de una caída de p exige una subida de p / (1 - p), así que una caída del 50% necesita un 100% y una del 80% necesita un 400%. Las variaciones sucesivas se multiplican y forman una progresión geométrica en lugar de una suma, que es el crecimiento que modela la herramienta de secuencias numéricas.
La variación de un valor antiguo a uno nuevo es (new - old) / old x 100, que es lo que la calculadora de porcentajes da como diferencia. Quitar un IVA del 20% significa dividir entre 1,2, no restar un 20%. Promediar porcentajes de grupos de tamaños distintos da una cifra global equivocada salvo que la media esté ponderada, y que la herramienta de suma y media muestre una mediana junto a la media hace visible ese sesgo.
Números formateados para una configuración regional
El formato es una decisión de presentación, y no es reversible sin conocer la configuración regional. 1.234 es uno y pico en el Reino Unido y mil en Alemania. 1,234 es justo al revés. Algunas configuraciones agrupan con un espacio o con un apóstrofo.
| Configuración regional | 1234567.89 |
|---|---|
| en-GB, en-US | 1,234,567.89 |
| de-DE | 1.234.567,89 |
| fr-FR | 1 234 567,89 |
| de-CH | 1'234'567.89 |
| en-IN | 12,34,567.89 |
La agrupación india coloca el primer separador después de tres dígitos y luego cada dos dígitos, lo que da lakhs y crores en lugar de miles y millones. Convertir una cadena formateada de vuelta en un número pierde información exactamente por este motivo, así que almacena y transmite los valores sin formatear y con un punto como separador decimal, y formatea solo en el momento de mostrarlos. Cuando un número tiene que ser inequívoco para quien lo lee, escribirlo con letras mediante la herramienta de números a palabras es lo que se hace en cheques y contratos. Los números romanos quedan fuera de todo esto: al no tener valor posicional ni cero, el conversor de números romanos maneja un recuento y no una base.