“ Bit-borrow” ตัวเลขสองตัว


20

คุณรู้หรือไม่ว่ามีจำนวนน้อยสามารถยืมบิตจากจำนวนที่มากขึ้นได้? นี่คือตัวอย่าง สมมุติว่าตัวเลขสองตัวของเราคือ 5 และ 14 ก่อนอื่นเขียนมันเป็นเลขฐานสอง:

5       14
000101  001110

ครั้งแรกที่เราใช้เวลาที่เล็กที่สุดในบิตห่างจากจำนวนมากและเราจะให้มันไปที่เล็กที่สุดออกบิตกับจำนวนอื่น ๆ ดังนั้น

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

ช่องโหว่มาตรฐานนำไปใช้และคำตอบที่สั้นที่สุดในไบต์ชนะ!

คำตอบ:


12

เยลลี่ 11 ไบต์

~1¦&N$^µ</¿

ลองออนไลน์! หรือตรวจสอบกรณีทดสอบทั้งหมด

พื้นหลัง

เราสามารถแยกบิตชุดสุดท้ายของจำนวนเต็มnดังนี้

n + 1สลับบิตชุดที่ต่อท้ายทั้งหมดของnและบิตที่ไม่ได้ติดตั้ง ยกตัวอย่างเช่น10011 2 + 1 = 10100 2

ตั้งแต่~ n = - (n + 1) = -n - 1 , -n = ~ n + 1ดังนั้น-nจะใช้ค่าที่อยู่เหนือกับ bitwise ไม่ใช่ของn (ซึ่งจะสลับบิตทั้งหมด ) จึงสลับบิตทั้งหมดก่อนหน้าสุดท้าย1 .

ยกตัวอย่างเช่น-10,100 2 = ~ 10100 2 + 1 = 01011 2 + 1 = 01100 2

โดยการใช้N & -nบิตและnและ-nบิตทั้งหมดก่อนบิตชุดสุดท้ายจะเป็นโมฆะ (ตั้งแต่ไม่เท่ากันในnและ-n ) จึงยอมบิตชุดสุดท้ายของn

ยกตัวอย่างเช่น10100 2 & -10,100 2 = 10100 2 & 01100 2 = 00100 2

ดังนั้น XORing nกับN & -n unsets บิตชุดสุดท้ายของn

ตรงกันข้ามเพื่อล้างค่าบิตชุดสุดท้ายของnก็พอเพียงที่จะนำไปใช้ด้านบนเพื่อ~ n , จากที่เราได้รับมาสูตรn ^ (~ 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 ) บิตขวาสุด ( 1 ) บิตสำหรับค่าnคุณสามารถดำเนินการบิต - และระหว่างnและn -1 และเพื่อเปิด (ตั้งค่า1 ) ขวาสุด off ( 0 ) bit สำหรับค่าnคุณสามารถดำเนินการ bitwise - หรือระหว่าง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

@DrGreenEggsandIronMan 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

ขอขอบคุณที่ @ มาร์ตินสำหรับการบันทึก 1 ~ไบต์และเตือนฉันของการประยุกต์ใช้มัด

การใช้

อินพุตประกอบด้วยอาร์กิวเมนต์จำนวนเต็มสองตัวและเอาต์พุตเป็นรายการที่มีค่าบิตที่ยืม

ตัวอย่าง


คิดว่าฉันจะลองสิ่งที่ตลก แต่น่าเสียดายที่มันเป็นไบต์นานกว่า: #//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}&(บางทีคุณอาจมีความคิดว่าจะย่อให้สั้นลงได้อย่างไร)
Martin Ender

นั่นเป็นกฎที่เรียบร้อย แต่ฉันไม่ค่อยคุ้นเคยกับกฎการตีกอล์ฟ ฉันมักจะใช้ทดแทนการและเงื่อนไข/. /;Wish Mathematica สามารถสลับไปมาระหว่างบูลีนและบิทคอยน์โดยตรวจสอบประเภทอาร์กิวเมนต์เป็น&&เช่นนั้น
ไมล์

3

Pyth, 29 27 25 22 21 20 19 18 16 ไบต์

MxG ^ 2x _ + \ 0.BG`HCm.W <FHgVZU2dC 
MxG ^ 2x_ + 0jG2HCm.W <FHgVZU2dC 
ซม. <FH.bxN ^ 2x_ + 0jN2YZ2dC
 m.W <FH.bxN ^ 2x_ + 0jN2YZ2       <- เปลี่ยนแปลงอินพุต / เอาต์พุต ฟอร์แมต
 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

@DrGreenEggsandIronMan มันบันทึกเพียงหนึ่งไบต์ Pyth เป็นที่มีประสิทธิภาพ
Leun Nun


2

เขาวงกต , 37 34 ไบต์

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

ลองออนไลน์!

คำอธิบาย

สีรองพื้นเขาวงกตอย่างรวดเร็ว:

  • Labyrinth ทำงานกับจำนวนเต็มสองจำนวนที่มีความแม่นยำตามอำเภอใจหลักและตัวช่วยเสริมซึ่งจะถูกเติมเต็มด้วยค่าศูนย์ (โดยปริยาย) จำนวนอนันต์
  • ซอร์สโค้ดมีลักษณะคล้ายเขาวงกตที่ซึ่งตัวชี้คำแนะนำ (IP) เป็นไปตามทางเดิน การควบคุมการไหลที่น่าสนใจทั้งหมดเกิดขึ้นที่ทางแยก: เมื่อ IP มีมากกว่าหนึ่งเซลล์ไปที่ด้านบนสุดของสแต็กหลักจะถูกตรวจสอบ หากค่าเป็นลบ IP จะเลี้ยวซ้ายถ้าเป็นบวก IP จะเลี้ยวขวามิฉะนั้นจะเลื่อนไปข้างหน้า หากทิศทางที่ถูกเลือกถูกบล็อกโดยกำแพง (เช่นช่องว่าง) IP จะเคลื่อนที่ในทิศทางตรงกันข้ามแทน

โปรแกรมใช้อัลกอริทึมเดียวกันกับคำตอบอื่น ๆ : เราแทนที่(a, b)ด้วย(a | a+1, b & b-1)ตราบใดที่a < bตราบใดที่ฉันจะเพิ่มคำอธิบายแบบเต็มหลังจากที่ฉันลองเล่นกอล์ฟเพิ่มเติม

IP เริ่มที่มุมซ้ายบนไปทางขวา อ่านจำนวนเต็ม? aจากนั้น"คือไม่มีการป้อนข้อมูล แต่จำเป็นต้องป้องกันไม่ให้ IP เคลื่อนลงทันที นี้ยังเป็นปลายตายดังนั้น IP หันไปรอบ ๆ และดำเนินการอีกครั้งในการอ่าน? จากนั้นย้ายจากmainไปยังauxดังนั้นตอนนี้เรามี:b}b

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

|แล้วไม่ทำอะไรเลยเพราะมันใช้เวลาบิตหรือของและa 0เมื่อเรารู้ว่าaเป็นบวกอยู่เสมอ IP จะเปลี่ยนเป็นทิศตะวันออก (เพราะไม่สามารถเลี้ยวตะวันตกได้) นี่เป็นการเริ่มลูปหลักของโปรแกรม เราเริ่มต้นด้วยส่วนของเส้นตรงสั้น ๆ เพื่อเปรียบเทียบaและb:

=   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

@DrGreenEggsandIronMan แก้ไขแล้ว Btw มักจะเป็นวิธีที่ไม่ดีในการเปลี่ยนกฎหลังจากที่ผู้คนโพสต์คำตอบของพวกเขาแล้ว แต่อย่างที่คุณบอกว่าควรลดจำนวนไบต์ดังนั้นฉันจึงตกลง (PS: คุณยังไม่ได้แสดงความคิดเห็นข้างต้นกับคำตอบของทุกคน)
Kevin Cruijssen

1
คุณสามารถเขียนwhileวนซ้ำของคุณเช่นนี้ได้for(;x<y;x|=x+1,y&=y-1);
หน้าผา

ฉันรู้ว่ามันเป็น -_-ฉันหวังว่าฉันจะเขียนได้ดีขึ้นตั้งแต่ต้น โชคดีที่มันไม่ใช่การเปลี่ยนแปลงที่ไม่สมเหตุสมผลหรือรุนแรง ใช่ฉันไม่ได้ให้ความเห็นทุกคำตอบ แต่ฉันแจ้งผู้ใช้ทุกคน ฉันไม่อยากแจ้งผู้ใช้คนเดียวกันหลายครั้ง ฉันไม่ได้แสดงความคิดเห็นในโพสต์ของ Dennis แต่นั่นเป็นเพราะเขาเป็นหนึ่งในผู้ใช้ที่สนับสนุนให้ฉันเปลี่ยนมันในตอนแรก
DJMcMayhem

1

JavaScript (ES6), 33 ไบต์

f=(n,m)=>n<m?f(n|n+1,m&m-1):[n,m]

พอร์ตที่เรียบง่ายของคำตอบโดย @miles


คุณลืมf=จุดเริ่มต้นของนักกีฬา: P
Mama Fun Roll

1
คุณลืม "อีกครั้ง" ;-)
Neil

1

Julia, 27 ไบต์

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

ลองออนไลน์!

มันทำงานอย่างไร

เรากำหนดผู้ประกอบการแบบไบนารี<|สำหรับวัตถุประสงค์ของเรา มันไม่ได้กำหนดไว้ใน Julia เวอร์ชันล่าสุด แต่ยังคงได้รับการยอมรับว่าเป็นตัวดำเนินการโดย parser ในขณะที่\(ไม่ได้ระบุอย่างชัดเจนสำหรับจำนวนเต็ม) จะสั้นกว่าหนึ่งไบต์ แต่มีความสำคัญสูงกว่าจะต้องแทนที่x|-~x<|y&~-yด้วย(x|-~x)\(y&~-y)ซึ่งจะเป็นการเพิ่มจำนวนไบต์

<|ตรวจสอบว่าอาร์กิวเมนต์แรกนั้นน้อยกว่าอย่างที่สอง ถ้าเป็นเช่นนั้นมันจะเรียกซ้ำตัวเองพร้อมอาร์กิวเมนต์x | - ~ x = x | (x + 1)และy & ~ -y = y & (y - 1)1)

ตั้งแต่เพิ่ม1ถึงxเพื่อสลับบิตชุดท้ายทั้งหมดและบิตที่ไม่ได้ตั้งค่าต่ำสุด, x | (x + 1)สลับบิตที่ไม่มีการตั้งค่าต่ำสุด (และไม่มีบิตอื่น) เช่นเดียวกันเนื่องจากการลบ1จากy เพื่อสลับบิตที่ไม่ได้ตั้งค่าทั้งหมดและบิตที่ถูกตั้งค่าต่ำสุด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])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.