El binario, el octal y el hexadecimal (también conocido como hex) son distintos sistemas de numeración con bases diferentes. El binario es base 2, el octal es base 8 y el hexadecimal es base 16. Los enteros normales son base 10 en Crystal. El binario, el octal y el hexadecimal son representaciones de números enteros. Esto significa que representan números positivos y negativos (incluido el cero) sin fracciones ni decimales, y admiten todas las operaciones que podemos hacer con números enteros.
El binario es un sistema de numeración de base 2 que usa solo los dígitos 0 y 1. Suele representar los estados 0 («apagado») y 1 («encendido») del flujo eléctrico a través de transistores e interruptores en las computadoras, así como las cargas positiva y negativa en los medios de almacenamiento magnético. El binario puede representar todos los números enteros que se usan en base 10.
Un fragmento del sistema de base 2 se ve así, aunque continúa infinitamente y no se detiene en 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 |
Entonces, si queremos representar el número 6, en binario sería: 110
| Valor posicional | 4 | 2 | 1 |
|---|---|---|---|
| Número binario | 1 | 1 | 0 |
Y la operación sería: 4 + 2 + 0 = 6
Otro ejemplo: 19
| Valor posicional | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|
| Número binario | 1 | 0 | 0 | 1 | 1 |
El número binario sería: 10011
Y la operación sería: 16 + 0 + 0 + 2 + 1 = 19
En Crystal, podemos representar literales binarios usando el prefijo 0b.
Si escribimos 0b10011, Crystal lo interpretará como un número binario y lo convertirá a base 10.
0b10011
# => 19
typeof(0b10011)
# => Int32
Si escribes un número con el prefijo 0b que no esté en el sistema binario, se generará un error de compilación.
0b10211
# => Error: unexpected token: "211"
Como los números binarios son enteros, podemos realizar con ellos todas las operaciones que podemos hacer con enteros.
0b10011 + 0b10011
# => 38
0b10011 * 0b10011
# => 361
0b10011 / 3
# => 6.333333333333333
Crystal convertirá automáticamente un literal binario a Int32.
Para convertir un Int32 a una representación binaria, usa el método <int>.to_s(base) con el argumento base establecido en 2.
El método devolverá una representación en string del número binario:
19.to_s(2)
# => "10011"
Para convertir una representación en string de un binario a un entero, podemos usar el método <int>.to_i(base), pasando la base (2) como argumento:
"10011".to_i(2)
# => 19
Dar la base incorrecta (o una representación binaria no válida) generará un ArgumentError:
"011021".to_i(2)
# => Invalid Int32: "011021" (ArgumentError)
Hay ciertos métodos que se pueden usar en los enteros para obtener información sobre la representación binaria del número.
<int>.bit_length devolverá la cantidad de bits que se necesitan para representar el número:
19.bit_length
# => 5
<int>.bit(index) devolverá el bit en el índice dado, empezando por la derecha (el bit menos significativo):
19.bit(0)
# => 1
0b10011.bit(1)
# => 1
El octal es un sistema de numeración de base 8. Usa los dígitos 0, 1, 2, 3, 4, 5, 6 y 7.
En Crystal, podemos representar números octales usando el prefijo 0o.
Al igual que con el binario, Crystal convierte automáticamente una representación octal a un Int32.
0o123
# => 83
Poner el prefijo 0o a un número que no esté en el sistema octal generará un error de compilación.
Al igual que con el binario, podemos usar el método <int>.to_s(base) para convertir un Int32 a una representación octal.
Y podemos usar el método <int>.to_i(base) para convertir una representación octal a un Int32.
83.to_s(8)
# => "123"
"123".to_i(8)
# => 83
Al igual que con el binario, dar la base incorrecta generará un ArgumentError.
El hexadecimal es un sistema de numeración de base 16. Usa los dígitos 0 - 9 y las letras A, B, C, D, E y F. A es 10, B es 11, C es 12, D es 13, E es 14 y F es 15.
Podemos representar números hexadecimales en Crystal usando el prefijo 0x.
Al igual que con el binario y el octal, Crystal convertirá automáticamente los literales hexadecimales a Int32.
#=> 0x123
291
Poner el prefijo 0x a un número que no sea hexadecimal generará un error de compilación.
Al igual que con el binario, podemos usar el método <int>.to_s(base) para convertir un Int32 a una representación hexadecimal.
Y podemos usar el método <int>.to_i(base) para convertir una representación hexadecimal a un Int32.
291.to_s(16)
# => "123"
"123".to_i(16)
# => 291
Al igual que con el binario y el octal, dar la base incorrecta generará un ArgumentError.
Al convertir un número a una representación en string, podemos especificar la precisión del número.
Es decir, la cantidad mínima de números usados para representar el número.
Si el número tiene menos dígitos que la precisión, se agregarán ceros a la izquierda a la representación en string.
Esto se hace pasando el argumento precision al método <int>.to_s(<base>, precision: <value>).
291.to_s(16, precision: 5)
# => "00123"
543.to_s(precision: 2)
# => "543"
Tu amigo se cansó de pagar por un software de edición de fotos y decidió escribir el suyo. Tu amigo decidió llamar al nuevo software Foto Fusionist.
Foto Fusionist es un software de edición de fotos que puede hacer muchas cosas, pero hasta ahora solo has implementado algunas. Sin embargo, tu amigo está muy contento con el progreso y te pidió que implementes algunas funcionalidades más.
Para la primera funcionalidad, tu amigo quiere poder convertir la representación binaria de un número a un número entero. Esto es necesario porque el software podrá leer la representación binaria de un canal de color y convertirla a un número entero.
Implementa el método FotoFusionist.binary_to_int, que recibe un argumento binary de tipo String.
El método debe devolver la representación del número binario como número entero.
FotoFusionist.binary_to_int("10011")
# => 19
La segunda funcionalidad que quiere tu amigo es poder obtener el bit menos significativo de un número entero. El bit menos significativo es el bit que está más a la derecha. Se llama bit menos significativo porque es el que tiene el menor valor.
El bit menos significativo es necesario para evaluar si una imagen se puede optimizar reduciendo la cantidad de bits que se usan para representar el canal de color.
Implementa el método FotoFusionist.least_significant_bit, que recibe un argumento number de tipo Int32.
El método debe devolver el bit menos significativo del número.
FotoFusionist.least_significant_bit(0b10011)
# => 1
FotoFusionist.least_significant_bit(0b10010)
# => 0
La tercera funcionalidad que quiere tu amigo es poder obtener el valor hexadecimal de un canal de color. El valor hexadecimal es necesario para poder convertir el canal de color a una representación hexadecimal, y esa representación hexadecimal debe estar formada por dos dígitos.
Implementa el método FotoFusionist.hex_value, que recibe un argumento number de tipo Int32.
El método debe devolver el valor hexadecimal del número como un String.
FotoFusionist.hex_value(19)
# => "13"
La cuarta funcionalidad que quiere tu amigo es poder obtener el valor hexadecimal de un color RGB. Esto es necesario para que quien use el programa pueda obtener una única representación de un color como string. Un color RGB es un color que se representa mediante tres canales de color: rojo, verde y azul. Cada canal de color se representa con un número entre 0 y 255.
El valor hexadecimal de un color RGB es una representación del color en hexadecimal como string, con el canal de color rojo primero, luego el canal de color verde y por último el canal de color azul.
Implementa el método FotoFusionist.hex_value_from_rgb, que recibe tres argumentos: red, green y blue de tipo Int32.
El método debe devolver el valor hexadecimal del color RGB como un String.
FotoFusionist.hex_value_from_rgb(255, 0, 0)
# => "ff0000"
Regístrate en Exercism para aprender y dominar Crystal con 26 conceptos142 ejercicios y mentoría humana real, todo gratis.