有理数的按位XOR


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)

where prefix是初始部分010suffix是重复部分0011int并将二进制字符串转换为整数。

给定两个这样的表示,我们可以对它们执行按位XOR操作。结果序列也将是周期性的,因此它表示一个有理数。

对于某些有理数,有两种二进制表示形式。

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

它们之间的选择会影响按位异或的结果。在这些情况下,我们使用前一个表示形式,该表示形式具有无限多个0。

任务

您的输入是半开区间[0,1)中的两个有理数。您的输出应为应用于输入的按位XOR运算的结果,以有理数表示。请注意,即使两个输入都不是,输出也可以为1。

输入和输出的确切格式是灵活的,但每个有理数应该由两个整数分子和分母(具有0和1之外,其可以被表示为被表示01如果需要的话)。您可以假设输入用最低术语表示。输出必须用最低的术语表示。内置有理数类型是可以接受的格式,只要它满足这些限制。您可以忽略语言所强加的整数的任何界限,但理论上,算法应适用于所有有理数。

最低字节数获胜。适用标准规则。

考虑输入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/323/24由于我们选择的展开0.101000...,所以我们得到了5/8。如果我们选择0.10011111...as作为5/8,则XOR之后的结果变为19/24,所以这是错误的。有关维基百科:0.999 ...
Jeppe Stig Nielsen

3
@JeppeStigNielsen Damn ...这意味着与常规XOR不同,(a ^ b) ^ b == a它不成立。例如(19/24 ^ 1/3) ^ 1/3 != 19/24。这让我对此非常兴奋:(
orlp

Answers:


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

将输入作为Python 3的fractions.Fraction类型,并输出它。

有趣的事实(您可以使用生成函数轻松显示这一点),如果更改(a<.5)^(b<.5)((a>=.5)and(b>=.5))上述内容,则会得到两个有理数之间的二进制与。叫这个nd(a, b)。那我们有a + b - 2*nd(a, b) = x(a, b)


确实,我的错。道歉!(请注意,答案中包含指向tio的链接会很棒)
Xcoder先生17年

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 / qy = r * b / q; 转换p / qr / sx / by / b;
  3. o = 10 ^ (p - q) - 1; 裂xy[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)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.