Побітове ХОР раціональних чисел


19

Вступ

Кожне раціональне число між 0 і 1 може бути представлене як кінцево періодична послідовність бітів. Наприклад, двійкове представлення 11/40 є

0.010 0011 0011 0011 ...

де 0011частина повторюється нескінченно. Один із способів пошуку цього уявлення полягає в наступному. Почніть з r = 11/40 , потім повторно подвоюйте її і діліть дробову частину, записуючи, коли вона перевищує 1. Коли значення r повторюється, ви знаєте, що ви ввели цикл.

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.

Щоб повернутися з двійкового рядка до рівня 11/40, ви можете використовувати формулу

(int(prefix) + int(suffix)/(2^len(suffix) - 1)) / 2^len(prefix)

де prefixпочаткова частина 010, suffixє повторювана частина 0011і intперетворює двійковий рядок у ціле число.

Враховуючи два таких подання, ми можемо виконувати над ними побітову операцію XOR. Отримана послідовність також буде періодичною, тому вона являє собою раціональне число.

Для деяких раціональних чисел існує два двійкових подання.

1/4 = 0.010000000...
    = 0.001111111...

Вибір між ними може вплинути на результат побітового XOR. У цих випадках ми використовуємо колишнє представлення, яке має нескінченно багато 0.

Завдання

Ваші входи - це два раціональних числа в напіввідкритому інтервалі [0,1). Ваш вихід повинен бути результатом побітової операції XOR, застосованої до входів, вираженої як раціональне число. Зауважте, що вихід може бути рівним 1, хоча жоден із входів не є.

Точні формати введення та виведення є гнучкими, але кожне раціональне число повинно бути представлене двома цілими числами - чисельником і знаменником (за винятком 0 і 1, які можна представити як 0і 1за бажанням). Можна припустити, що вхідні дані виражаються найнижчою кількістю. Вихід повинен бути виражений найменшими показниками. Вбудований раціональний тип числа є прийнятним форматом, якщо він задовольняє цим обмеженням. Ви можете ігнорувати будь-які межі на цілі числа, накладені вашою мовою, але ваш алгоритм повинен теоретично працювати для всіх раціональних чисел.

Виграє найменший байт. Діють стандартні правила .

Приклад

Розглянемо входи 11/40 та 3/7. Ми пишемо їх зображення один над одним, розмежуючи труби, що повторюються |. Потім витягуємо повторювані частини однакової довжини і прикладаємо до них біт XOR і частини перед ними.

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 ...

Отримане раціональне число - 89/520.

Тестові справи

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

Який максимальний термін нам потрібно підтримувати?
Ніл

@Neil Що змушує вас думати, що такий максимум існує?
orlp

3
Примітка: Деякі числа мають два двійкові розширення, а саме ті числа, де можливий період має довжину один. У вищезазначеному визначенні проблеми мається на увазі, що ми повинні вибрати представлення, яке закінчується000...в цьому випадку (що також ми отримуємо, якщо використовувати алгоритмr). Наприклад, в разі5/8, 1/3ми отримуємо23/24тому що ми вибираємо розширення0.101000...для5/8. Якщо ми виберемо замість0.10011111...як5/8, результат після XOR стає19/24, то це неправильно. Пов’язане з Вікіпедією: 0,999 ...
Джеппе Стіг Нільсен

3
@JeppeStigNielsen Чорт ... Це означає, що на відміну від звичайного XOR (a ^ b) ^ b == aне дотримується. Напр (19/24 ^ 1/3) ^ 1/3 != 19/24. Це змусило мене втратити трохи хвилювання з цього приводу :(
orlp

Відповіді:


3

Python 3, 193 164 байт

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

Приймає дані як fractions.Fractionтип Python 3 , а також виводить його.

Забавний факт (ви можете легко показати це за допомогою функцій генерації), якщо перейти (a<.5)^(b<.5)на ((a>=.5)and(b>=.5))вище, ви отримаєте двійкове І між двома раціональними числами. Телефонуйте це nd(a, b). Тоді маємо a + b - 2*nd(a, b) = x(a, b)!


Справді, моя помилка. Вибачте! (зауважте, що посилання на tio, включене у відповідь, було б чудово)
Містер Xcoder

1

JavaScript, 141 байт

(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))

Не буду працювати для останнього тестового випадку (ціле число переповнення). Введіть 4 числа для p/q xor r/s, виведіть масив з двома числами. Для тестової скриньки 0, 0слід ввести 0, 1, 0, 1.

Як:

(Усі числа, описані тут, є у двійковій формі.)

  1. знайти найменше число b, яке b = 10 ^ p - 10 ^ q (p, q are integers, p > q); and b = 0 (mod q); and b = 0 (mod s);
  2. Нехай x = p * b / q, y = r * b / q; Перетворити p / q, r / sв x / bі y / b;
  3. Нехай o = 10 ^ (p - q) - 1; поділ x, yщоб [x % o, x / o], [y % o, y / o]; отримати xor для кожної частини [x % o xor y % o, x / o xor y / o]та приєднатися до (x % o xor y % o) + (x / o xor y / o) * o; Пожертвуйте як a;
  4. Якщо a = 0, відповідь 0(або 0 / 1); Інакше нехай u = gcd(a, b); відповідь - (a/u)і (b/u).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.