O binário, o octal e o hexadecimal (também conhecido como hex) são sistemas de numeração diferentes, com bases diferentes. O binário é base 2, o octal é base 8 e o hexadecimal é base 16. Em Crystal, os números inteiros normais são base 10. O binário, o octal e o hexadecimal são todos representações de números inteiros. Isto significa que representam números positivos e negativos (incluindo o zero) sem frações nem casas decimais, e suportam todas as operações que podemos fazer com números inteiros.
O binário é um sistema de numeração de base 2, que usa apenas os algarismos 0 e 1. Representa habitualmente os estados 0 («desligado») e 1 («ligado») do fluxo elétrico através de transístores e interruptores nos computadores, bem como as cargas positivas e negativas nos suportes de armazenamento magnético. O binário pode representar todos os números inteiros que se usam na base 10.
Um excerto do sistema de base 2 é o seguinte, embora continue infinitamente e não pare em 128:
| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|
| 2 ** 7 | 2 ** 6 | 2 ** 5 | 2 ** 4 | 2 ** 3 | 2 ** 2 | 2 ** 1 | 2 ** 0 |
Por isso, se quisermos representar o número 6, em binário seria: 110
| Valor posicional | 4 | 2 | 1 |
|---|---|---|---|
| Número binário | 1 | 1 | 0 |
E a operação seria: 4 + 2 + 0 = 6
Outro exemplo: 19
| Valor posicional | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|
| Número binário | 1 | 0 | 0 | 1 | 1 |
O número binário seria: 10011
E a operação seria: 16 + 0 + 0 + 2 + 1 = 19
Em Crystal, podemos representar literais binários com o prefixo 0b.
Se escrevermos 0b10011, o Crystal interpreta-o como um número binário e converte-o para a base 10.
0b10011
# => 19
typeof(0b10011)
# => Int32
Se escreveres um número com o prefixo 0b que não esteja no sistema binário, o Crystal gera um erro de compilação.
0b10211
# => Error: unexpected token: "211"
Como os números binários são inteiros, podemos realizar neles todas as operações que podemos fazer com números inteiros.
0b10011 + 0b10011
# => 38
0b10011 * 0b10011
# => 361
0b10011 / 3
# => 6.333333333333333
O Crystal converte automaticamente um literal binário num Int32.
Para converter um Int32 numa representação binária, usa o método <int>.to_s(base) com o argumento base definido como 2.
O método devolve uma representação em string do número binário:
19.to_s(2)
# => "10011"
Para converter uma representação em string de um binário num número inteiro, podemos usar o método <int>.to_i(base), passando a base (2) como argumento:
"10011".to_i(2)
# => 19
Indicar a base errada (ou uma representação binária inválida) gera um ArgumentError:
"011021".to_i(2)
# => Invalid Int32: "011021" (ArgumentError)
Há certos métodos que podem ser usados em números inteiros para obter informações sobre a representação binária do número.
O <int>.bit_length devolve o número de bits necessários para representar o número:
19.bit_length
# => 5
O <int>.bit(index) devolve o bit no índice indicado, começando pela direita (bit menos significativo):
19.bit(0)
# => 1
0b10011.bit(1)
# => 1
O octal é um sistema de numeração de base 8. Usa os algarismos 0, 1, 2, 3, 4, 5, 6 e 7.
Em Crystal, podemos representar números octais com o prefixo 0o.
Tal como no binário, o Crystal converte automaticamente uma representação octal num Int32.
0o123
# => 83
Se colocares o prefixo 0o num número que não pertença ao sistema octal, o Crystal gera um erro de compilação.
Tal como no binário, podemos usar o método <int>.to_s(base) para converter um Int32 numa representação octal.
E podemos usar o método <int>.to_i(base) para converter uma representação octal num Int32.
83.to_s(8)
# => "123"
"123".to_i(8)
# => 83
Tal como no binário, indicar a base errada gera um ArgumentError.
O hexadecimal é um sistema de numeração de base 16. Usa os algarismos 0 a 9 e as letras A, B, C, D, E e F. A é 10, B é 11, C é 12, D é 13, E é 14 e F é 15.
Podemos representar números hexadecimais em Crystal com o prefixo 0x.
Tal como no binário e no octal, o Crystal converte automaticamente os literais hexadecimais em Int32.
#=> 0x123
291
Se colocares o prefixo 0x num número que não seja hexadecimal, o Crystal gera um erro de compilação.
Tal como no binário, podemos usar o método <int>.to_s(base) para converter um Int32 numa representação hexadecimal.
E podemos usar o método <int>.to_i(base) para converter uma representação hexadecimal num Int32.
291.to_s(16)
# => "123"
"123".to_i(16)
# => 291
Tal como no binário e no octal, indicar a base errada gera um ArgumentError.
Quando convertemos um número numa representação em string, podemos especificar a precisão do número.
Ou seja, a quantidade mínima de algarismos usada para representar o número.
Se o número tiver menos algarismos do que a precisão, são acrescentados zeros à esquerda da representação em string.
Isto faz-se passando o argumento precision ao método <int>.to_s(<base>, precision: <value>).
291.to_s(16, precision: 5)
# => "00123"
543.to_s(precision: 2)
# => "543"
O teu amigo cansou-se de pagar por software de edição de fotografias e decidiu escrever o seu próprio. O teu amigo decidiu chamar ao novo software Foto Fusionist.
O Foto Fusionist é um software de edição de fotografias que consegue fazer muitas coisas, mas até agora só implementaste algumas delas. No entanto, o teu amigo está muito contente com o progresso e pediu-te para implementares mais algumas funcionalidades.
Para a primeira funcionalidade, o teu amigo quer conseguir converter a representação binária de um número num inteiro. Isto é feito porque o software vai poder ler a representação binária de um canal de cor e convertê-la num inteiro.
Implementa o método FotoFusionist.binary_to_int, que recebe um argumento binary do tipo String. O método deve devolver o inteiro representado pelo número binário.
FotoFusionist.binary_to_int("10011")
# => 19
A segunda funcionalidade que o teu amigo quer é conseguir obter o bit menos significativo de um inteiro. O bit menos significativo é o bit que está mais à direita. Chama-se bit menos significativo porque é o que tem o valor mais baixo.
O bit menos significativo é necessário para avaliar se uma imagem pode ser otimizada reduzindo o número de bits usados para representar o canal de cor.
Implementa o método FotoFusionist.least_significant_bit, que recebe um argumento number do tipo Int32. O método deve devolver o bit menos significativo do número.
FotoFusionist.least_significant_bit(0b10011)
# => 1
FotoFusionist.least_significant_bit(0b10010)
# => 0
A terceira funcionalidade que o teu amigo quer é conseguir obter o valor hexadecimal de um canal de cor. O valor hexadecimal é necessário para converter o canal de cor numa representação hexadecimal, e a representação hexadecimal dada tem de ser composta por dois algarismos.
Implementa o método FotoFusionist.hex_value, que recebe um argumento number do tipo Int32. O método deve devolver o valor hexadecimal do número como uma String.
FotoFusionist.hex_value(19)
# => "13"
A quarta funcionalidade que o teu amigo quer é conseguir obter o valor hexadecimal de uma cor RGB. Isto é necessário para que o utilizador consiga obter uma única string que representa uma cor. Uma cor RGB é uma cor representada por três canais de cor: vermelho, verde e azul. Cada canal de cor é representado por um número entre 0 e 255.
O valor hexadecimal de uma cor RGB é uma representação em string da cor em hexadecimal, primeiro com o canal de cor vermelho, depois o canal de cor verde e, por último, o canal de cor azul.
Implementa o método FotoFusionist.hex_value_from_rgb, que recebe três argumentos: red, green e blue, do tipo Int32. O método deve devolver o valor hexadecimal da cor RGB como uma String.
FotoFusionist.hex_value_from_rgb(255, 0, 0)
# => "ff0000"
Inscreve-te no Exercism para aprenderes e dominares Crystal com 26 conceitos142 exercícios, e mentoria humana real, tudo grátis.