introduzione
Ogni numero razionale compreso tra 0 e 1 può essere rappresentato come una sequenza di bit eventualmente periodica. Ad esempio, la rappresentazione binaria di 11/40 è
0.010 0011 0011 0011 ...
dove la 0011
parte si ripete indefinitamente. Un modo per trovare questa rappresentazione è il seguente. Inizia con r = 11/40 , quindi raddoppia ripetutamente e prendi la parte frazionaria, registrando quando supera 1. Quando il valore di r si ripete, sai di essere entrato in un ciclo.
1. r = 11/40
2. 2*r = 11/20 < 1 -> next bit is 0, r = 11/20
3. 2*r = 11/10 >= 1 -> next bit is 1, r = 2*r - 1 = 1/10
4. 2*r = 1/5 < 1 -> next bit is 0, r = 1/5
5. 2*r = 2/5 < 1 -> next bit is 0, r = 2/5
6. 2*r = 4/5 < 1 -> next bit is 0, r = 4/5
7. 2*r = 8/5 >= 1 -> next bit is 1, r = 2*r - 1 = 3/5
8. 2*r = 6/5 >= 1 -> next bit is 1, r = 2*r - 1 = 1/5, same as in 4.
The loop 5. -> 6. -> 7. -> 8. now repeats.
Per tornare dalla stringa binaria a 11/40, è possibile utilizzare la formula
(int(prefix) + int(suffix)/(2^len(suffix) - 1)) / 2^len(prefix)
dove prefix
è la parte iniziale 010
, suffix
è la parte ripetuta 0011
e int
converte una stringa binaria in numero intero.
Date due di queste rappresentazioni, possiamo eseguire l'operazione XOR bit a bit su di esse. Anche la sequenza risultante sarà periodica, quindi rappresenta un numero razionale.
Per alcuni numeri razionali, ci sono due rappresentazioni binarie.
1/4 = 0.010000000...
= 0.001111111...
La scelta tra loro può influenzare il risultato dell'XOR bit a bit. In questi casi, usiamo la rappresentazione precedente, che ha infinitamente molti 0.
L'obiettivo
I tuoi input sono due numeri razionali nell'intervallo semi-aperto [0,1). L'output deve essere il risultato dell'operazione XOR bit a bit applicata agli input, espressa come un numero razionale. Si noti che l'uscita può essere 1, anche se nessuno degli ingressi lo è.
I formati esatti di input e output sono flessibili, ma ogni numero razionale dovrebbe essere rappresentato da due numeri interi, il numeratore e il denominatore (ad eccezione di 0 e 1, che possono essere rappresentati come 0
e 1
se desiderato). Si può presumere che gli input siano espressi in termini più bassi. L'output deve essere espresso nei termini più bassi. Un tipo di numero razionale incorporato è un formato accettabile, purché soddisfi queste restrizioni. Puoi ignorare qualsiasi limite sugli interi imposti dal tuo linguaggio, ma il tuo algoritmo dovrebbe teoricamente funzionare per tutti i numeri razionali.
Vince il conteggio dei byte più basso. Si applicano le regole standard del code-golf .
Esempio
Considera gli ingressi 11/40 e 3/7. Scriviamo le loro rappresentazioni una sopra l'altra, delimitando le parti ripetute con le pipe |
. Quindi estraiamo parti ripetute di uguale lunghezza e applichiamo XOR bit a bit a esse e alle parti prima di esse.
11/40 = 0. 0 1 0|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 1|0 0 1 ...
3/7 = 0.|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|0 1 1|...
-> 0. 0 0 1|0 1 0 1 1 1 1 0 1 0 0 0|0 1 0 1 1 1 1 0 1 0 0 0|0 1 0 ...
Il numero razionale risultante è 89/520.
Casi test
0 0 -> 0
1/2 1/2 -> 0
1/2 1/4 -> 3/4
1/3 2/3 -> 1
1/2 3/4 -> 1/4
5/8 1/3 -> 23/24
1/3 1/5 -> 2/5
15/16 3/19 -> 257/304
15/16 257/304 -> 3/19
3/7 11/40 -> 89/520
5/32 17/24 -> 59/96
16/29 16/39 -> 621001733121535520/696556744961512799
000...
in questi casi (che è anche ciò che otteniamo se usiamo l'algoritmo conr
). Ad esempio, nel caso5/8, 1/3
otteniamo23/24
perché scegliamo l'espansione0.101000...
per5/8
. Se scegliamo invece0.10011111...
come5/8
, il risultato dopo XOR diventa19/24
, quindi questo è sbagliato. Correlato a Wikipedia: 0.999 ...
(a ^ b) ^ b == a
non regge. Es (19/24 ^ 1/3) ^ 1/3 != 19/24
. Questo mi ha fatto perdere un po 'di eccitazione per questo :(