Binário, octal e hexadecimal (também chamado de 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 inteiros normais são base 10. Binário, octal e hexadecimal são todos representações de inteiros. Isso significa que eles representam números positivos e negativos (incluindo o zero) sem frações ou decimais e dão suporte a todas as operações que podemos fazer com inteiros.
Binário é um sistema de numeração de base 2, que usa apenas os dígitos 0 e 1. Ele costuma representar os estados 0 ("desligado") e 1 ("ligado") do fluxo elétrico através de transistores e interruptores nos computadores, assim como as cargas positiva e negativa nos meios de armazenamento magnético. O binário consegue representar todos os inteiros usados na base 10.
Um trecho do sistema de base 2 é assim, embora ele continue infinitamente e não pare no 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 |
Então, se quisermos representar o número 6, em binário ele 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 usando o prefixo 0b.
Se escrevermos 0b10011, o Crystal vai interpretá-lo como um número binário e convertê-lo para a base 10.
0b10011
# => 19
typeof(0b10011)
# => Int32
Se você escrever um número com o prefixo 0b que não esteja no sistema binário, isso vai lançar um erro de compilação.
0b10211
# => Error: unexpected token: "211"
Como números binários são inteiros, podemos realizar neles todas as operações que fazemos com inteiros.
0b10011 + 0b10011
# => 38
0b10011 * 0b10011
# => 361
0b10011 / 3
# => 6.333333333333333
O Crystal converte automaticamente um literal binário em Int32.
Para converter um Int32 em uma representação binária, use o método <int>.to_s(base) com o argumento de base definido como 2.
O método retorna 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 em um inteiro, podemos usar o método <int>.to_i(base), passando a base (2) como argumento:
"10011".to_i(2)
# => 19
Informar a base errada (ou uma representação binária inválida) vai lançar um ArgumentError:
"011021".to_i(2)
# => Invalid Int32: "011021" (ArgumentError)
Existem alguns métodos que podem ser usados em inteiros para obter informações sobre a representação binária do número.
<int>.bit_length retorna o número de bits necessários para representar o número:
19.bit_length
# => 5
<int>.bit(index) retorna o bit no índice informado, começando da direita (bit menos significativo):
19.bit(0)
# => 1
0b10011.bit(1)
# => 1
Octal é um sistema de numeração de base 8. Ele usa os dígitos 0, 1, 2, 3, 4, 5, 6 e 7.
Em Crystal, podemos representar números octais usando o prefixo 0o.
Assim como no binário, o Crystal converte automaticamente uma representação octal em um Int32.
0o123
# => 83
Colocar o prefixo 0o em um número que não esteja no sistema octal vai lançar um erro de compilação.
Assim como no binário, podemos usar o método <int>.to_s(base) para converter um Int32 em uma representação octal.
E podemos usar o método <int>.to_i(base) para converter uma representação octal em um Int32.
83.to_s(8)
# => "123"
"123".to_i(8)
# => 83
Assim como no binário, informar a base errada vai lançar um ArgumentError.
Hexadecimal é um sistema de numeração de base 16. Ele usa os dígitos de 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 usando o prefixo 0x.
Assim como no binário e no octal, o Crystal converte automaticamente literais hexadecimais em Int32.
#=> 0x123
291
Colocar o prefixo 0x em um número que não seja hexadecimal vai lançar um erro de compilação.
Assim como no binário, podemos usar o método <int>.to_s(base) para converter um Int32 em uma representação hexadecimal.
E podemos usar o método <int>.to_i(base) para converter uma representação hexadecimal em um Int32.
291.to_s(16)
# => "123"
"123".to_i(16)
# => 291
Assim como no binário e no octal, informar a base errada vai lançar um ArgumentError.
Ao converter um número para uma representação em string, podemos especificar a precisão do número.
Ou seja, a quantidade mínima de números usada para representar o número.
Se o número tiver menos dígitos que a precisão, zeros à esquerda serão adicionados à representação em string.
Isso é feito passando o argumento precision para o método <int>.to_s(<base>, precision: <value>).
291.to_s(16, precision: 5)
# => "00123"
543.to_s(precision: 2)
# => "543"
Seu amigo se cansou de pagar por software de edição de fotos e decidiu escrever o próprio. Seu amigo decidiu chamar o novo software de Foto Fusionist.
O Foto Fusionist é um software de edição de fotos que consegue fazer muitas coisas, mas você só implementou algumas delas até agora. Mesmo assim, seu amigo está muito feliz com o progresso e pediu que você implementasse mais alguns recursos.
Para o primeiro recurso, seu amigo quer conseguir converter a representação binária de um número em um inteiro. Isso é feito porque o software conseguirá ler a representação binária de um canal de cor e convertê-la em um inteiro.
Implemente o método FotoFusionist.binary_to_int, que recebe um argumento binary do tipo String.
O método deve retornar a representação inteira do número binário.
FotoFusionist.binary_to_int("10011")
# => 19
O segundo recurso que seu amigo quer é conseguir obter o bit menos significativo de um inteiro. O bit menos significativo é o bit que fica mais à direita. Ele é chamado de bit menos significativo porque tem o menor valor.
O bit menos significativo é necessário para avaliar se uma imagem pode ser otimizada, reduzindo a quantidade de bits usada para representar o canal de cor.
Implemente o método FotoFusionist.least_significant_bit, que recebe um argumento number do tipo Int32.
O método deve retornar o bit menos significativo do número.
FotoFusionist.least_significant_bit(0b10011)
# => 1
FotoFusionist.least_significant_bit(0b10010)
# => 0
O terceiro recurso que seu amigo quer é conseguir obter o valor hexadecimal de um canal de cor. O valor hexadecimal é necessário para converter o canal de cor em uma representação hexadecimal, e a representação hexadecimal fornecida precisa ser composta por dois dígitos.
Implemente o método FotoFusionist.hex_value, que recebe um argumento number do tipo Int32.
O método deve retornar o valor hexadecimal do número como uma String.
FotoFusionist.hex_value(19)
# => "13"
O quarto recurso que seu amigo quer é conseguir obter o valor hexadecimal de uma cor RGB. Isso é necessário para que a pessoa usuária possa obter uma única representação em string de 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, com o canal de cor vermelho primeiro, depois o canal de cor verde e, por fim, o canal de cor azul.
Implemente o método FotoFusionist.hex_value_from_rgb, que recebe três argumentos: red, green e blue, do tipo Int32.
O método deve retornar o valor hexadecimal da cor RGB como uma String.
FotoFusionist.hex_value_from_rgb(255, 0, 0)
# => "ff0000"
Crie sua conta no Exercism para aprender e dominar Crystal com 26 conceitos142 exercícios e mentoria humana de verdade, tudo de graça.