Il binario, l'ottale e l'esadecimale (noto anche come hex) sono diversi sistemi di numerazione, con basi diverse. Il binario è in base 2, l'ottale in base 8 e l'esadecimale in base 16. In Crystal, i normali numeri interi sono in base 10. Il binario, l'ottale e l'esadecimale sono tutte rappresentazioni di numeri interi. Questo significa che rappresentano numeri positivi e negativi (incluso lo zero) senza frazioni o decimali e supportano tutte le operazioni che possiamo fare con i numeri interi.
Il binario è un sistema di numerazione in base 2, che usa solo le cifre 0 e 1. Rappresenta comunemente gli stati 0 («off») e 1 («on») del flusso elettrico attraverso transistor e interruttori nei computer, così come le cariche positive e negative nei supporti di memorizzazione magnetica. Il binario può rappresentare tutti i numeri interi che si usano in base 10.
Uno stralcio del sistema in base 2 è questo, anche se continua all'infinito e non si ferma a 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 |
Quindi, se vogliamo rappresentare il numero 6, in binario sarebbe: 110
| Place value | 4 | 2 | 1 |
|---|---|---|---|
| Binary number | 1 | 1 | 0 |
E l'operazione sarebbe: 4 + 2 + 0 = 6
Un altro esempio: 19
| Place value | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|
| Binary number | 1 | 0 | 0 | 1 | 1 |
Il numero binario sarebbe: 10011
E l'operazione sarebbe: 16 + 0 + 0 + 2 + 1 = 19
In Crystal, possiamo rappresentare i letterali binari usando il prefisso 0b.
Se scriviamo 0b10011, Crystal lo interpreterà come numero binario e lo convertirà in base 10.
0b10011
# => 19
typeof(0b10011)
# => Int32
Se scrivi un numero con il prefisso 0b che non è nel sistema binario, verrà generato un errore di compilazione.
0b10211
# => Error: unexpected token: "211"
Dato che i numeri binari sono numeri interi, possiamo eseguire su di essi tutte le operazioni che possiamo fare con i numeri interi.
0b10011 + 0b10011
# => 38
0b10011 * 0b10011
# => 361
0b10011 / 3
# => 6.333333333333333
Crystal convertirà automaticamente un letterale binario in Int32.
Per convertire un Int32 in una rappresentazione binaria, usa il metodo <int>.to_s(base) con l'argomento base impostato a 2.
Il metodo restituirà una rappresentazione sotto forma di stringa del numero binario:
19.to_s(2)
# => "10011"
Per convertire la rappresentazione di un binario sotto forma di stringa in un numero intero, possiamo usare il metodo <int>.to_i(base), passando la base (2) come argomento:
"10011".to_i(2)
# => 19
Indicare la base sbagliata (o una rappresentazione binaria non valida) genererà un ArgumentError:
"011021".to_i(2)
# => Invalid Int32: "011021" (ArgumentError)
Esistono alcuni metodi che si possono usare sui numeri interi per ottenere informazioni sulla rappresentazione binaria del numero.
<int>.bit_length restituirà il numero di bit necessari per rappresentare il numero:
19.bit_length
# => 5
<int>.bit(index) restituirà il bit all'indice indicato, partendo da destra (bit meno significativo):
19.bit(0)
# => 1
0b10011.bit(1)
# => 1
L'ottale è un sistema di numerazione in base 8. Usa le cifre 0, 1, 2, 3, 4, 5, 6 e 7.
In Crystal, possiamo rappresentare i numeri ottali usando il prefisso 0o.
Come per il binario, Crystal converte automaticamente una rappresentazione ottale in un Int32.
0o123
# => 83
Scrivere un numero con il prefisso 0o che non è nel sistema ottale genererà un errore di compilazione.
Come per il binario, possiamo usare il metodo <int>.to_s(base) per convertire un Int32 in una rappresentazione ottale.
E possiamo usare il metodo <int>.to_i(base) per convertire una rappresentazione ottale in un Int32.
83.to_s(8)
# => "123"
"123".to_i(8)
# => 83
Come per il binario, indicare la base sbagliata genererà un ArgumentError.
L'esadecimale è un sistema di numerazione in base 16. Usa le cifre da 0 a 9 e le lettere A, B, C, D, E e F. A è 10, B è 11, C è 12, D è 13, E è 14 e F è 15.
Possiamo rappresentare i numeri esadecimali in Crystal usando il prefisso 0x.
Come per il binario e l'ottale, Crystal convertirà automaticamente i letterali esadecimali in Int32.
#=> 0x123
291
Scrivere un numero non esadecimale con il prefisso 0x genererà un errore di compilazione.
Come per il binario, possiamo usare il metodo <int>.to_s(base) per convertire un Int32 in una rappresentazione esadecimale.
E possiamo usare il metodo <int>.to_i(base) per convertire una rappresentazione esadecimale in un Int32.
291.to_s(16)
# => "123"
"123".to_i(16)
# => 291
Come per il binario e l'ottale, indicare la base sbagliata genererà un ArgumentError.
Quando convertiamo un numero in una rappresentazione sotto forma di stringa, possiamo specificare la precisione del numero.
Ovvero il numero minimo di cifre usate per rappresentare il numero.
Se il numero ha meno cifre della precisione, alla rappresentazione sotto forma di stringa verranno aggiunti degli zeri iniziali.
Per farlo, si passa l'argomento precision al metodo <int>.to_s(<base>, precision: <value>).
291.to_s(16, precision: 5)
# => "00123"
543.to_s(precision: 2)
# => "543"
Il tuo amico si è stancato di pagare per un software di fotoritocco e ha deciso di scriverne uno tutto suo. Ha deciso di chiamare il nuovo software Foto Fusionist.
Foto Fusionist è un software di fotoritocco in grado di fare molte cose, ma finora ne hai implementate solo alcune. Il tuo amico però è molto soddisfatto dei progressi e ti ha chiesto di implementare qualche altra funzionalità.
Come prima funzionalità, il tuo amico vuole poter convertire la rappresentazione binaria di un numero in un numero intero. Serve perché il software possa leggere la rappresentazione binaria di un canale di colore e convertirla in un numero intero.
Implementa il metodo FotoFusionist.binary_to_int, che accetta un argomento binary di tipo String. Il metodo deve restituire la rappresentazione come numero intero del numero binario.
FotoFusionist.binary_to_int("10011")
# => 19
La seconda funzionalità che il tuo amico vuole è poter ottenere il bit meno significativo da un numero intero. Il bit meno significativo è il bit più a destra. Si chiama bit meno significativo perché ha il valore più piccolo.
Il bit meno significativo serve a valutare se un'immagine può essere ottimizzata riducendo il numero di bit usati per rappresentare il canale di colore.
Implementa il metodo FotoFusionist.least_significant_bit, che accetta un argomento number di tipo Int32. Il metodo deve restituire il bit meno significativo del numero.
FotoFusionist.least_significant_bit(0b10011)
# => 1
FotoFusionist.least_significant_bit(0b10010)
# => 0
La terza funzionalità che il tuo amico vuole è poter ottenere il valore esadecimale da un canale di colore. Il valore esadecimale serve per poter convertire il canale di colore in una rappresentazione esadecimale, e tale rappresentazione deve essere composta da due cifre.
Implementa il metodo FotoFusionist.hex_value, che accetta un argomento number di tipo Int32. Il metodo deve restituire il valore esadecimale del numero come String.
FotoFusionist.hex_value(19)
# => "13"
La quarta funzionalità che il tuo amico vuole è poter ottenere il valore esadecimale da un colore RGB. Serve a permettere a chi usa il software di ottenere una rappresentazione del colore come un'unica stringa. Un colore RGB è un colore rappresentato da tre canali di colore: rosso, verde e blu. Ogni canale di colore è rappresentato da un numero compreso tra 0 e 255.
Il valore esadecimale di un colore RGB è la rappresentazione del colore in esadecimale, con prima il canale rosso, poi il canale verde e infine il canale blu.
Implementa il metodo FotoFusionist.hex_value_from_rgb, che accetta tre argomenti: red, green e blue di tipo Int32. Il metodo deve restituire il valore esadecimale del colore RGB come String.
FotoFusionist.hex_value_from_rgb(255, 0, 0)
# => "ff0000"
Iscriviti a Exercism per imparare e padroneggiare Crystal con 26 concetti142 esercizi e il mentoring di persone reali, tutto gratis.