XOR bit a bit di numeri razionali


19

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 0011parte 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 0011e intconverte 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 0e 1se 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 .

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

Qual è il periodo massimo che dobbiamo sostenere?
Neil,

@Neil Cosa ti fa pensare che esista un tale massimo?
orlp

3
Nota: alcuni numeri hanno due espansioni binarie, vale a dire quei numeri in cui il periodo finale ha una lunghezza. È implicito nella definizione del problema sopra che dobbiamo scegliere la rappresentazione che termina000...in questi casi (che è anche ciò che otteniamo se usiamo l'algoritmo conr). Ad esempio, nel caso5/8, 1/3otteniamo23/24perché 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 ...
Jeppe Stig Nielsen

3
@JeppeStigNielsen Damn ... Ciò significa che a differenza del normale XOR (a ^ b) ^ b == anon regge. Es (19/24 ^ 1/3) ^ 1/3 != 19/24. Questo mi ha fatto perdere un po 'di eccitazione per questo :(
orlp

Risposte:


3

Python 3, 193 164 byte

def x(a,b,z=0):
 l=[]
 while(a,b)not in l:l+=[(a,b)];z=2*z|(a<.5)^(b<.5);a=a*2%1;b=b*2%1
 p=l.index((a,b));P=len(l)-p
 return((z>>P)+z%2**P*a**0/~-2**(P or 1))/2**p

Prende l'input come tipo di Python 3 fractions.Fractione lo emette anche.

Una curiosità (si può mostrare facilmente questo utilizzando funzioni generatrici), se si cambia (a<.5)^(b<.5)di ((a>=.5)and(b>=.5))sopra si ottiene l'AND binario tra due numeri razionali. Chiama questo nd(a, b). Quindi abbiamo a + b - 2*nd(a, b) = x(a, b)!


Anzi, il mio errore. Scuse! (nota che un link a tio incluso nella risposta sarebbe fantastico)
Mr. Xcoder

1

JavaScript, 141 byte

(p,q,r,s)=>(h=(v,u)=>v%u?h(u,v%u):[a/u,b/u])(b=(g=x=>x%q||x%s?g((x|x/2)+x%2):x)(1),a=(o=b/(b-(b&~-b)),x=p*b/q,y=r*b/s,(x%o^y%o)+(x/o^y/o)*o))

Non funziona per l'ultimo caso di test (overflow intero). Immettere 4 numeri per p/q xor r/s, generare un array con due numeri. Per testcase 0, 0, è necessario inserire 0, 1, 0, 1.

Come:

(Tutti i numeri descritti qui sono in forma binaria.)

  1. trova il numero più piccolo b, che b = 10 ^ p - 10 ^ q (p, q are integers, p > q); and b = 0 (mod q); and b = 0 (mod s);
  2. Let x = p * b / q, y = r * b / q; Converti p / q, r / sin x / be y / b;
  3. Let o = 10 ^ (p - q) - 1; spaccato x, ydi [x % o, x / o], [y % o, y / o]; ottenere xor per ogni parte [x % o xor y % o, x / o xor y / o]e ricollegarsi a (x % o xor y % o) + (x / o xor y / o) * o; Donalo come a;
  4. Se a = 0la risposta è 0(o 0 / 1); Altrimenti lascia u = gcd(a, b); la risposta è (a/u)e (b/u).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.