Bases numéricas, tamanhos em bytes e as unidades que dão discussão

Como o hexadecimal se mapeia nos bits, porque é que um disco de 1 TB aparece como 931 GB, quanto dá realmente 0,1 mais 0,2, e como o arredondamento, as percentagens e a formatação por localidade alteram um número sem se dar por isso.

Um número escrito transporta duas coisas: um valor e um conjunto de pressupostos sobre como deve ser lido. 0xFF, 255, 0o377 e 11111111 são uma só quantidade em quatro notações. Um terabyte e um tebibyte diferem em dez por cento. 1,234 é aproximadamente mil em Londres e aproximadamente um em Berlim. A maioria dos erros com números vem dos pressupostos e não da aritmética.

Binário, octal, decimal e hexadecimal

Todas as bases posicionais funcionam da mesma maneira. Cada casa vale a base vezes a casa à sua direita, e os dígitos vão de zero até à base menos um. A base 16 precisa de mais seis dígitos, por isso vai buscar A a F para representar dez a quinze.

O hexadecimal é usado para bytes e para cores porque 16 é 2 elevado a 4, por isso um dígito hexadecimal são exatamente quatro bits e um byte são exatamente dois dígitos hexadecimais, sem transporte entre eles.

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

Essa tabela é toda a conversão. Para passar de hexadecimal a binário, substitua cada dígito pelos seus quatro bits: 0x2F passa a 0010 1111. Para voltar, agrupe os bits de quatro em quatro a partir da direita, preenchendo a esquerda com zeros, e leia cada grupo na tabela.

Para o decimal, use os valores posicionais. 0x2F é 2 x 16 + 15, ou seja 47. No sentido contrário, divida repetidamente por 16 e leia os restos de baixo para cima:

200 / 16 = 12 remainder 8   -> 8
 12 / 16 =  0 remainder 12  -> C
200 decimal = 0xC8

O octal empacota três bits por dígito, e é por isso que as permissões do Unix se escrevem como 755: cada dígito é um trio rwx, sendo 7 igual a 111 e 5 igual a 101. Uma cor CSS como #FF8800 são três bytes, um por canal, cada um a ir de 0 a 255, e a forma abreviada de três dígitos #F80 expande-se duplicando cada dígito e não preenchendo com zeros. O Number Base Converter cobre as quatro bases ao mesmo tempo.

Complemento para dois, e de onde vêm as gamas

Um byte comporta 256 padrões distintos. Lidos como sem sinal, vão de 0 a 255. Lidos como com sinal, o bit mais alto marca a metade negativa, e um valor negativo é o seu padrão menos 256. Esse esquema é o complemento para dois, escolhido porque a adição binária vulgar passa assim a funcionar de forma idêntica com valores com e sem sinal.

Para negar um número, inverta todos os bits e some um. A gama é assimétrica porque o zero ocupa uma das 128 posições da metade não negativa, pelo que um byte com sinal vai de -128 a 127. Somar um ao topo da gama dá a volta para o fundo:

  0111 1111    127
+ 0000 0001      1
= 1000 0000   -128

Na maioria das linguagens nada é assinalado; o valor limita-se a aparecer do outro lado da gama. A mesma volta com 32 bits é o problema de 2038, em que um timestamp Unix de 32 bits com sinal se esgota aos 2 147 483 647 segundos. Dezasseis bits sem sinal dão de 0 a 65 535, que é exatamente a razão por que os números de porta TCP acabam aí, e por que o Random Port Generator escolhe dentro dessa gama evitando as portas reservadas abaixo de 1024.

Kilobytes, kibibytes e os gigabytes em falta

Os fabricantes de armazenamento contam em potências de dez. Os sistemas operativos contaram historicamente em potências de dois e rotularam o resultado com o prefixo decimal, e é aí que começa a discussão. Os prefixos binários (KiB, MiB, GiB) existem para eliminar a ambiguidade.

Potência de dezValor decimalPrefixo binárioValor binárioDiferença
kB, 10^31000KiB, 2^1010242,4%
MB, 10^61 000 000MiB, 2^201 048 5764,9%
GB, 10^91 000 000 000GiB, 2^301 073 741 8247,4%
TB, 10^121 000 000 000 000TiB, 2^401 099 511 627 77610,0%
PB, 10^1510^15PiB, 2^501 125 899 906 842 62412,6%

Um disco de 1 TB contém 10^12 bytes tal como é vendido. Divida isso por 2^30 e obtém 931,32, por isso o Windows indica cerca de 931 GB, usando o rótulo decimal para uma quantidade binária. Não falta nada; os mesmos bytes estão apenas a ser divididos por outro número. O macOS e a maior parte das ferramentas de Linux indicam hoje GB decimais, o que coincide com a caixa. Os tamanhos de memória são genuinamente binários, por isso 16 GB de RAM são mesmo 16 GiB.

As velocidades de rede contam-se em bits, não em bytes, e sempre em decimal. Uma linha de 100 Mbps transporta 100 000 000 bits por segundo, ou seja 12,5 MB por segundo antes da sobrecarga. A sobrecarga do protocolo leva alguns por cento, por isso 11 a 12 MB por segundo é o teto realista. Dividir por oito um valor anunciado em megabits é a verificação rápida, e o Unit Converter cobre as unidades de armazenamento.

Vírgula flutuante, e porque é que dinheiro não é um float

As frações binárias só conseguem representar somas de metades, quartos, oitavos e por aí fora. Um décimo não tem forma binária exata, tal como um terço não tem forma decimal exata, por isso 0.1 guardado como um double IEEE 754 é ligeiramente mais do que um décimo. Some duas aproximações destas e o erro vem ao de cima:

0.1 + 0.2 = 0.30000000000000004

Um double tem 53 bits de mantissa. Isso torna exatamente representável qualquer inteiro até 2^53 (9 007 199 254 740 992), bem como qualquer fração cujo denominador seja uma potência de dois. Acima de 2^53 o intervalo entre valores representáveis passa a 2, pelo que 2^53 + 1 é igual a 2^53. É por isto que os identificadores de base de dados de 64 bits enviados por JSON devem viajar como cadeias de carateres: os números em JavaScript são doubles, e um ID de 19 dígitos perde os últimos dígitos sem avisar.

Para dinheiro, guarde subunidades inteiras (cêntimos) ou use um tipo decimal que trabalhe em base dez. Nunca compare floats por igualdade; compare a diferença com uma pequena tolerância. O Expression Calculator também trabalha em doubles e herda os mesmos limites.

Arredondar, e arredondar duas vezes

O modo half up leva um empate para longe do zero. O half even, também chamado arredondamento bancário, leva um empate para o dígito par mais próximo, o que elimina o enviesamento para cima que o half up introduz ao longo de uma coluna comprida de valores. É o modo por omissão do IEEE 754 e a regra em várias normas contabilísticas.

ValorHalf upHalf even
0,510
1,522
2,532
3,544
-0,5-10

Arredonde uma só vez, a partir do valor original. Arredondar 2,4449 a três casas decimais dá 2,445, e arredondar esse valor a duas dá 2,45, ao passo que arredondar o original diretamente a duas dá 2,44. O arredondamento encadeado através de colunas intermédias é uma fonte comum de totais errados por um cêntimo. Uma surpresa aparentada: 2,675 arredonda para 2,67 na maioria das linguagens, porque o double guardado é 2,67499999999999982.

Por cento e ponto percentual

Uma taxa que passa de 4% para 5% subiu um ponto percentual, ou 25% em termos relativos. As duas afirmações estão corretas, e a unidade tem de ser indicada.

As variações percentuais não se anulam. Uma queda de 50% seguida de uma subida de 50% deixa 75, e não 100, porque a segunda percentagem é calculada sobre uma base mais pequena. Recuperar de uma queda de p exige uma subida de p / (1 - p), por isso uma queda de 50% precisa de 100% e uma queda de 80% precisa de 400%. As variações sucessivas multiplicam-se, formando uma sequência geométrica e não uma soma, que é o crescimento que a ferramenta Number Sequence modela.

A variação de um valor antigo para um valor novo é (new - old) / old x 100, que é o que o Percentage Calculator apresenta como diferença. Retirar 20% de IVA significa dividir por 1,2, não subtrair 20%. Fazer a média de percentagens de grupos com tamanhos diferentes dá um valor global errado, a não ser que a média seja ponderada, e o Sum and Average, ao mostrar a mediana ao lado da média, torna a assimetria visível.

Números formatados para uma localidade

A formatação é uma decisão de apresentação e não é reversível sem se conhecer a localidade. 1.234 é um e pouco no Reino Unido e mil na Alemanha. 1,234 é o contrário. Algumas localidades agrupam antes com um espaço ou com um apóstrofo.

Localidade1234567.89
en-GB, en-US1,234,567.89
de-DE1.234.567,89
fr-FR1 234 567,89
de-CH1'234'567.89
en-IN12,34,567.89

O agrupamento indiano coloca o primeiro separador ao fim de três dígitos e, a partir daí, de dois em dois dígitos, dando lakh e crore em vez de milhares e milhões. Ler uma cadeia formatada de volta para um número perde informação exatamente por esta razão, por isso guarde e transmita os valores sem formatação, com um ponto como separador decimal, e formate só no momento da apresentação. Quando um número tem de ser inequívoco para quem o lê, escrevê-lo por extenso com o Number to Words é a prática habitual em cheques e em contratos. Os numerais romanos ficam fora de tudo isto: sem valor posicional e sem zero, o Roman Numeral Converter está a lidar com uma contagem por marcas e não com uma base.