“借位”两个数字


20

您是否知道少数可以从较大的数字位?这是一个例子。假设我们的两个数字分别为5和14。首先,将它们写成二进制:

5       14
000101  001110

首先,我们从较大的数字中减去最小的on位,然后将其赋予其他数字中的最小off位。所以

This bit turns off
            |
            v
000101  001110
    ^
    |
This bit turns on

现在我们有

000111  001100

我们的数字是7和12。第一个数字仍然较小,因此我们继续。

000111  001100
001111  001000

现在我们有15和8,所以我们可以停下来。我们将这组操作称为“借位”两个数字。让我们再举一个例子。20和61。

20        61
010100    111101
010101    111100
010111    111000
111111    100000
63        32

因此,我们最终的结果是32,63,让我们做一个更多。31和12。31已经大于12,因此无事可做!借位31和12不会产生31和12的变化。

挑战

您的挑战是编写一个接受两个数字并对其进行位借位的程序或函数。这两个数字将始终为正整数。您的输入和输出可以采用任何合理的格式。

测试IO:

Input: 2, 3
Output: 3, 2

Input: 3, 2
Output: 3, 2

Input: 8, 23
Output: 31, 0

Input: 42, 81
Output: 63, 0

Input: 38, 41
Output: 47, 32

Input: 16, 73
Output: 23, 0

Input: 17, 17
Output: 17, 17

存在标准漏洞,最短答案以字节为单位!

Answers:


12

果冻,11 字节

~1¦&N$^µ</¿

在线尝试!验证所有测试用例

背景

我们可以提取整数的最后一个设置位 n

n + 1间切换的所有尾部比特集合Ñ和相邻的未设置位。例如10011 2 +1 = 10100 2

由于〜n =-(n + 1)= -n-1-n =〜n + 1,因此-n将以上内容应用于n的按位非(这会切换所有位),从而切换最后一位之前的所有位1

例如,-10100 2 =〜10100 2 + 1 = 01011 2 + 1 = 01100 2

通过采取N'-n的位与ñ-n在所有位的最后一组位被废止之前(因为不平等ñ-n),因而产生的最后一组位Ñ

例如10100 2和-10100 2 = 10100 2和01100 2 = 00100 2

因此,将nn&-n进行异或取消设置n的最后一个设置位。

相反,要取消设置n的最后一个设置位,只需将上述内容应用于〜n,从那里我们推导式N R个(〜n的& - 〜N)

怎么运行的

~1¦&N$^µ</¿  Main link. Argument: A (list of pairs)

          ¿  While loop:
        </     Condition: Reduce p by less-than. True iff x < y.
       µ       Body chain:
~1¦              Apply bitwise NOT to the x, first item of the pair.
     $           Convert the two links to the left into a monadic chain.
    N              Negate; multiply [~x, y] by -1, yielding [-~x, -y].
   &               Logical AND. Yields [-~x & ~x, -y & y].
      ^            Vectorized XOR with p. Yields [(-~x & ~x) ^ x, (-y & y) ^ y].

6

J,31 26字节

,`(($:~(OR>:))~(AND<:))@.<

使用递归和按位技巧的直接方法。为了关闭(设置为0)值n的最右边(1)位,您可以按位执行nn -1 之间的操作,并打开(设置为1)最右边的位将off(0)位设置为值n,可以按位或在n之间执行n +1。

用法

输入由两个整数组成,一个整数应用在LHS上,另一个整数应用在RHS上,输出是位借用值的列表。

   f =: ,`(($:~(OR>:))~(AND<:))@.<
   2 f 3
3 2
   3 f 2
3 2
   8 f 23
31 0
   42 f 81
63 0
   38 f 41
47 32
   16 f 73
23 0
   17 f 17
17 17

说明

,`(($:~(OR>:))~(AND<:))@.<  Input: x on LHS, y on RHS
                            If x < y,
,                             Form a 2-element array [x, y] and return
                            Else
                   <:         Decrement y
                AND           Perform bitwise-and on y and y-1, call it y'
          >:                  Increment x
        OR                    Perform bitwise-or on x and x+1, call it x'
    $:                        Call recursively on x' and y' and return

好答案!抱歉,在您发布答案后更改挑战,但是我已经稍微简化了挑战。(您无需再遍历该列表)。那应该让您将它缩短一些。
DJMcMayhem

@DrGreenEg​​gsandIronMan J实际上是在两个数组之间逐元素地应用函数,而没有任何明确的排名,这很好。除非有其他技巧,否则可能会保持不变。
英里

4

Python,42个字节

f=lambda x,y:x<y and f(x|x+1,y&y-1)or(x,y)

感谢@ jimmy23013高尔夫球了4个字节! 感谢@LeakyNun打高尔夫球2个字节!

Ideone上进行测试


3

Mathematica,46个字节

If[#<#2,BitOr[#,#+1]~#0~BitAnd[#2,#2-1],{##}]&

与我在J 解决方案中使用的方法相同。

感谢@ Martin保存了1个字节并让我想起了infix应用程序~

用法

输入由两个整数参数组成,输出是带有借位值的列表。

Example


以为我会尝试一些有趣的事情,但是不幸的是它要长一个字节:(#//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}&也许您知道如何缩短它)
Martin Ender

这是一个整洁的规则,但是我对打高尔夫球规则不是很熟悉。我通常只使用替换/.和条件/;。希望Mathematica可以通过检查&&诸如此类的参数类型来在布尔和按位之间切换。
2016年

3

佩斯,29 27 25 22 21 20 19 18 16字节

MxG ^ 2x _ + \ 0.BG`HCm.W <FHgVZU2dC 
MxG ^ 2x_ + 0jG2HCm.W <FHgVZU2dC
 Cm.W <FH.bxN ^ 2x_ + 0jN2YZ2dC 
m.W <FH.bxN ^ 2YZ + 2       输出格式
 mW <FH.exb ^ 2x_ + 0jb2kZ 
m.W <FH.U ,. | bhb。&ZtZZ 
.W <FH.U ,. | bhb。&ZtZZ          <-更改了输入/输出格式
 .W <FH.U ,. | bhb。&ZtZ
.W <FH.U ,. | bhb。&t

测试套件。


抱歉,在您发布答案后更改挑战,但是我已经稍微简化了挑战。(您无需再遍历该列表)。尽管值得庆幸的是,这可以使您缩短它。
DJMcMayhem

@DrGreenEg​​gsandIronMan它只保存了一个字节。Pyth 就是那么高效。
Leaky Nun


2

迷宫37 34字节

?"
}
|=:{:
)   }
: :;-{
=&( {!;\!@

在线尝试!

说明

快速迷宫底漆:

  • 迷宫运算在任意两个精度为整数的堆栈(整数和辅助整数)上运行,这些整数最初填充有(隐式)无限数量的零。
  • 源代码类似于迷宫,其中指令指针(IP)遵循走廊。所有有趣的控制流程都发生在结点:当IP有多个单元要访问时,将检查主堆栈的顶部。如果该值为负,则IP向左转;如果为正,则IP向右转,否则它将向前移动。如果所选方向被墙(即空间)阻挡,则IP朝相反的方向移动。

该程序使用相同的算法其他答案:我们替换(a, b)(a | a+1, b & b-1),只要a < b。在尝试打高尔夫球之后,我将添加完整的解释。

IP从左上角开始,向右移动。?读取一个整数a。这"是一个禁忌,但有必要防止IP立即下降。这也是一个死胡同,因此IP掉头并?再次执行以读取b}然后bmain移到aux,所以现在我们有了:

Main [ ... 0 a | b 0 ...] Aux

|则什么也不做,因为它需要的位或中a0。由于我们知道a永远是积极的,因此IP会向东(因为它不能向西)。这开始了程序的主循环。我们开始以比较短的直线段ab

=   Swap tops of stacks, i.e. swap a and b.
:   Duplicate b.
{   Pull a over to main.
:   Duplicate a.
}   Push one copy back to aux.
-   Compute b-a.

IP现在位于另一个交叉点。首先,让我们考虑结果为正的情况。这意味着b > a,我们需要再执行一次迭代。该迭代也是完全线性的。请注意,堆栈当前为:

Main [ ... 0 b (b-a) | a 0 ...] Aux

;   Discard b-a.
:   Duplicate b.
(   Decrement.
&   Bitwise AND with b, clearing the least-significant 1.
=   Swap new b with old a.
:   Duplicate a.
)   Increment.
|   Bitwise OR with a, setting the least-significant 0.

然后我们回到循环的起点(由于a再次为正,因此IP再次向东旋转)。

如果在某个时候b-a不再为正,则IP将采用其他两条路径之一。请注意,在这两种情况下,我们取a{,然后点击其中IP遵循弯曲一个角落里,然后打印a!。现在,堆栈的顶部再次出现b-a,这意味着在两种情况下,IP最终都将向东移动。现在剩下的只是一小段线性:

;   Discard b-a.
\   Print a linefeed.
!   Print b.
@   Terminate the program.

1

Java 7,73个字节

void d(int x,int y){while(x<y){x|=x+1;y&=y-1;}System.out.print(x+","+y);}

非高尔夫球和测试用例:

在这里尝试。

public class Main{
  static void d(int x, int y){
    while(x < y){
      x |= x + 1;
      y &= y - 1;
    }
    System.out.print(x + "," + y);
  }

  public static void main(String[] a){
    print(2, 3);
    print(3, 2);
    print(8, 23);
    print(42, 81);
    print(38, 41);
    print(16, 73);
    print(17, 17);
  }

  public static void print(int a, int b){
    d(a, b);
    System.out.println();
  }
}

输出:

3,2
3,2
31,0
63,0
47,32
23,0
17,17

旧挑战规则[ 126 125 123字节]:

注意:旧的质询规则使用两个整数数组作为输入,而不是两个零散的整数。

void d(int[]a,int[]b){int i=-1,x,y;while(++i<a.length){x=a[i];y=b[i];for(;x<y;x|=x+1,y&=y-1);System.out.println(x+","+y);}}

抱歉,在您发布答案后更改挑战,但是我已经稍微简化了挑战。(您无需再遍历该列表)。尽管值得庆幸的是,这可以使您缩短它。
DJMcMayhem

@DrGreenEg​​gsandIronMan编辑。顺便说一句,在人们发布答案后更改规则通常是一种不好的做法。但是正如您所说,它应该降低字节数,所以我可以接受。(PS:您尚未对所有人的回答发表以上评论。)
Kevin Cruijssen

1
您可以while像这样重写循环for(;x<y;x|=x+1,y&=y-1);
悬崖根

我知道它是。-_-我希望我从一开始就写得更好。幸运的是,这不是一个不合理或剧烈的变化。另外,是的,我没有对每个答案发表评论,但我通知了每个用户。我不想多次通知同一位用户。我没有评论Dennis的帖子,但这是因为他是鼓励我最初更改它的用户之一。
DJMcMayhem


1

朱莉娅,27个字节

x<|y=x<y?x|-~x<|y&~-y:[x,y]

在线尝试!

怎么运行的

我们<|为我们的目的定义了二进制运算符。它在Julia的最新版本中未定义,但仍被解析器识别为运算符。虽然\(未明确定义为整数)短了一个字节,但其高优先级将需要替换x|-~x<|y&~-y(x|-~x)\(y&~-y),从而增加了字节数。

<|检查其第一个参数是否严格小于第二个参数。如果是这样,它将以参数x |递归地调用自身-〜x = x | (x +1) y&〜-y = y&(y-1)

由于加入1 x切换所有尾随置位和最低未置位,因此x | (x + 1)切换最低未设置位(无其他位)。同样,由于从y中减去1会切换所有尾随的未设置位,而最低位则为y&(y + 1)会切换最低位。

最后,当不平等 x <y不再成立时,<|返回对[x,y]


0

MATLAB,67 66字节

环:

function[]=f(x,y)
while x<y
x=bitor(x,x+1);y=bitand(y,y-1);end
x,y

递归(67字节):

function[]=f(x,y)
if x<y
f(bitor(x,x+1),bitand(y,y-1))
else
x,y
end

改变位的方法与其他许多响应器相同。


0

Clojure,63个字节

#(if(< % %2)(recur(bit-or %(inc %))(bit-and %2(dec %2)))[% %2])

与我的方法相同 在J 解决方案中。

用法

=> (def f #(if(< % %2)(recur(bit-or %(inc %))(bit-and %2(dec %2)))[% %2]))
=> (f 38 41)
[47 32]
=> (map (partial apply f) [[2 3] [3 2] [8 23] [42 81] [38 41] [16 73] [17 17]])
([3 2] [3 2] [31 0] [63 0] [47 32] [23 0] [17 17])
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.