"Pinjam sedikit" dua angka

20

Tahukah Anda bahwa sejumlah kecil dapat meminjam bit dari jumlah yang lebih besar? Ini sebuah contoh. Katakanlah dua angka 5 dan 14. Pertama, tuliskan dalam biner:

5       14
000101  001110

Pertama kita mengambil terkecil di agak jauh dari jumlah yang lebih besar, dan kami memberikannya kepada yang terkecil off sedikit di nomor lain. Begitu

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

Sekarang kita punya

000111  001100

dan nomor kami adalah 7 dan 12. Angka pertama masih lebih kecil, jadi kami melanjutkan.

000111  001100
001111  001000

Sekarang kita punya 15 dan 8, jadi kita bisa berhenti. Kami akan menyebut rangkaian operasi ini "peminjaman bit" dua angka. Mari kita lakukan contoh lain. 20 dan 61.

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

Jadi hasil akhir kami adalah 32, 63. Mari kita lakukan satu lagi. 31, dan 12. 31 sudah lebih besar dari 12, jadi tidak ada yang bisa dilakukan! Pinjam bit 31 dan 12 memberi 31 dan 12, tanpa perubahan.

Tantangan

Tantangan Anda adalah menulis sebuah program atau fungsi yang mengambil dua angka dan meminjamnya sedikit. Dua angka akan selalu bilangan bulat positif. Input dan output Anda dapat dalam format apa pun yang masuk akal.

Tes 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

Celah standar berlaku, dan jawaban tersingkat dalam byte menang!

DJMcMayhem
sumber

Jawaban:

12

Jelly , 11 byte

~1¦&N$^µ</¿

Cobalah online! atau verifikasi semua kasus uji .

Latar Belakang

Kita dapat mengekstrak bit set terakhir dari integer n sebagai berikut.

n + 1 mengaktifkan semua bit set trailing n dan bit unset yang berdekatan. Misalnya, 10011 2 + 1 = 10100 2 .

Karena ~ n = - (n + 1) = -n - 1 , -n = ~ n + 1 , jadi -n menerapkan hal di atas ke bitwise BUKAN dari n (yang mengubah semua bit), sehingga mengubah semua bit sebelum yang terakhir 1 .

Misalnya, -10100 2 = ~ 10100 2 + 1 = 01011 2 + 1 = 01100 2 .

Dengan mengambil n & -n bitwise AND dari n dan -n semua bit sebelum bit set terakhir dibatalkan (karena tidak sama dengan n dan -n ), sehingga menghasilkan bit set terakhir dari n .

Misalnya, 10100 2 & -10100 2 = 10100 2 & 01100 2 = 00100 2 .

Jadi XORing n dengan n & -n mengeset bit set terakhir dari n .

Sebaliknya, untuk menghapus set bit terakhir dari n , cukup untuk menerapkan hal di atas ke ~ n , dari mana kita memperoleh rumus n ^ (~ n & - ~ n) .

Bagaimana itu bekerja

~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].
Dennis
sumber
6

J, 31 26 byte

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

Pendekatan lurus ke depan menggunakan rekursi dan trik bitwise. Untuk mematikan (set ke 0 ) bit paling kanan di ( 1 ) untuk nilai n , Anda dapat melakukan bitwise-dan antara n dan n -1, dan untuk menghidupkan (set ke 1 ) bit paling kanan off ( 0 ) bit untuk nilai n , Anda dapat melakukan bitwise-atau antara n dan n +1.

Pemakaian

Input terdiri dari dua bilangan bulat, satu diterapkan pada LHS dan yang lainnya pada RHS, dan outputnya adalah daftar nilai bit-borrowed.

   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

Penjelasan

,`(($:~(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
mil
sumber
Jawaban bagus! Maaf mengubah tantangan setelah Anda mengirim jawaban, tetapi saya sedikit menyederhanakan tantangan. (Anda tidak perlu mengulangi daftar lagi). Itu akan membuat Anda lebih pendek sedikit.
DJMcMayhem
@DrGreenEggsandIronMan J sebenarnya menerapkan elemen fungsi-bijaksana antara dua array tanpa peringkat eksplisit, yang bagus. Kecuali ada trik lain, itu mungkin akan tetap sama.
mil
4

Python, 42 byte

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

Terima kasih kepada @ jimmy23013 untuk bermain golf 4 byte! Terima kasih kepada @LeakyNun untuk bermain golf 2 byte!

Uji di Ideone .

Dennis
sumber
3

Mathematica, 46 byte

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

Metode yang sama seperti yang digunakan dalam solusi saya di J.

Terima kasih kepada @ Martin untuk menghemat 1 byte dan mengingatkan saya pada aplikasi infix ~.

Pemakaian

Input terdiri dari dua argumen integer dan output adalah daftar dengan nilai bit-borrowed.

Contoh

mil
sumber
Saya pikir saya akan mencoba sesuatu yang lucu, tapi sayangnya itu satu byte lebih lama: #//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}&(mungkin Anda punya ide bagaimana mempersingkatnya)
Martin Ender
Itu aturan yang rapi, tapi saya tidak terlalu terbiasa dengan aturan golf. Saya biasanya hanya menggunakan subtitusi /.dan ketentuan /;. Wish Mathematica dapat beralih antara boolean dan bitwise dengan memeriksa tipe argumen ke &&dan semacamnya.
mil
3

Pyth, 29 27 25 22 21 20 19 18 16 byte

MxG ^ 2x _ + \ 0.BG`HCm.W <FHgVZU2dC 
MxG ^ 2x_ + 0jG2HCm.W <FHgVZU2dC 
Cm.W <FH.bxN ^ 2x_ + 0jN2YZ2dC 
m.W <FH.bxN ^ 2x input + input       < 2Z format
 mW <FH.exb ^ 2x_ + 0jb2kZ 
m.W <FH.U ,. | bhb. & ZtZZ 
.W <FH.U ,. | bhb. & ZtZZ          <- mengubah input / output format
 .W <FH.U ,. | bhb. & ZtZ
.W <FH.U ,. | bhb. & T

Suite uji.

Biarawati Bocor
sumber
Maaf mengubah tantangan setelah Anda mengirim jawaban, tetapi saya sedikit menyederhanakan tantangan. (Anda tidak perlu mengulangi daftar lagi). Meskipun untungnya itu akan memungkinkan Anda untuk mempersingkatnya.
DJMcMayhem
@DrGreenEggsandIronMan Hanya menyimpan satu byte. Pyth adalah bahwa efisien.
Leaky Nun
2

05AB1E, 16 15 byte

[D`›#`D<&sD>~s‚

Cobalah online

Emigna
sumber
2

Labyrinth , 37 34 byte

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

Cobalah online!

Penjelasan

Primer Labirin Cepat:

  • Labyrinth beroperasi pada dua tumpukan bilangan bulat presisi arbitrer, utama dan tambahan , yang awalnya diisi dengan jumlah nol tak terbatas (implisit).
  • Kode sumber menyerupai labirin, tempat penunjuk instruksi (IP) mengikuti koridor. Semua aliran kontrol yang menarik terjadi di persimpangan: ketika IP memiliki lebih dari satu sel untuk pergi, bagian atas tumpukan utama diperiksa. Jika nilainya negatif, IP belok kiri, jika positif, IP belok kanan, dan jika tidak bergerak lurus ke depan. Jika arah yang dipilih diblokir oleh dinding (yaitu spasi), IP bergerak ke arah yang berlawanan.

Program ini menggunakan algoritma yang sama dengan jawaban lainnya: kami ganti (a, b)dengan (a | a+1, b & b-1)selama a < b. Saya akan menambahkan penjelasan lengkap setelah saya mencoba bermain golf lagi.

IP dimulai di sudut kiri atas, ke kanan. ?membaca bilangan bulat a. Maka "adalah no-op, tetapi perlu untuk mencegah IP dari turun segera. Ini juga jalan buntu, sehingga IP berbalik dan mengeksekusi ?lagi untuk membaca b. }lalu pindah bdari main ke aux , jadi sekarang kita punya:

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

The |kemudian tidak apa-apa, karena dibutuhkan bitwise OR adan 0. Karena kita tahu aselalu positif, IP berbelok ke timur (karena tidak bisa berbelok ke barat). Ini memulai lingkaran utama program. Kita mulai dengan bagian linier pendek untuk membandingkan adan 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 sekarang di persimpangan lain. Pertama, mari kita perhatikan kasus di mana hasilnya positif. Itu berarti b > adan kita perlu melakukan satu iterasi lagi. Iterasi itu juga sepenuhnya linier. Perhatikan bahwa tumpukan saat ini:

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.

Dan kemudian kita kembali ke awal dari loop (karena alagi positif, IP berbalik ke timur lagi).

Jika suatu saat b-atidak lagi positif, IP akan mengambil satu dari dua jalur lainnya. Perhatikan bahwa dalam kedua kasus kami menjemput adengan {, lalu tekan sudut di mana IP mengikuti tikungan dan kemudian mencetak adengan !. Sekarang bagian atas tumpukan lagi b-ayang berarti bahwa dalam kedua kasus IP akan berakhir bergerak ke timur. Yang tersisa adalah bit linear pendek sekarang:

;   Discard b-a.
\   Print a linefeed.
!   Print b.
@   Terminate the program.
Martin Ender
sumber
1

Java 7, 73 byte

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

Kasus yang tidak disatukan & uji:

Coba di sini.

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

Keluaran:

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

Aturan tantangan lama [ 126 125 123 byte]:

CATATAN: Aturan tantangan lama menggunakan dua bilangan bulat-array sebagai input, bukan dua bilangan bulat yang longgar.

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);}}
Kevin Cruijssen
sumber
Maaf mengubah tantangan setelah Anda mengirim jawaban, tetapi saya sedikit menyederhanakan tantangan. (Anda tidak perlu mengulangi daftar lagi). Meskipun untungnya itu akan memungkinkan Anda untuk mempersingkatnya.
DJMcMayhem
@DrGreenEggsandIronMan Diedit. Btw, itu biasanya praktik yang buruk untuk mengubah aturan setelah orang memposting jawaban mereka .. Tapi seperti yang Anda katakan, itu harus menurunkan byte-count, jadi saya setuju dengan itu. (PS: Anda belum membuat komentar di atas atas jawaban semua orang.)
Kevin Cruijssen
1
Anda dapat menulis ulang whilelingkaran Anda seperti inifor(;x<y;x|=x+1,y&=y-1);
cliffroot
Saya tahu itu. -_-Saya berharap saya telah menulisnya dengan lebih baik dari awal. Untungnya itu bukan perubahan yang tidak masuk akal atau drastis. Juga, ya saya tidak mengomentari setiap jawaban, tetapi saya memberi tahu setiap pengguna. Saya tidak ingin memberi tahu pengguna yang sama beberapa kali. Saya tidak mengomentari posting Dennis, tetapi itu karena dia adalah salah satu pengguna yang mendorong saya untuk mengubahnya pada awalnya.
DJMcMayhem
1

JavaScript (ES6), 33 byte

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

Port jawaban sederhana oleh @miles.

Neil
sumber
Anda lupa dengan f=awalnya: P
Mama Fun Roll
1
Anda lupa "lagi" ;-)
Neil
1

Julia, 27 byte

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

Cobalah online!

Bagaimana itu bekerja

Kami mendefinisikan operator biner <|untuk tujuan kami. Ini tidak terdefinisi dalam versi terbaru Julia, tetapi masih diakui sebagai operator oleh parser. Sementara \(tidak secara eksplisit didefinisikan untuk bilangan bulat) adalah salah satu byte lebih pendek, diutamakan yang tinggi akan membutuhkan menggantikan x|-~x<|y&~-ydengan (x|-~x)\(y&~-y), sehingga meningkatkan jumlah byte.

<|memeriksa apakah argumen pertamanya benar-benar kurang dari argumen kedua. Jika demikian, itu secara rekursif menyebut dirinya dengan argumen x | - ~ x = x | (x + 1) dan y & ~ -y = y & (y - 1) .

Karena menambahkan 1 ke x matikan semua bit set trailing dan bit unset terendah, x | (x +1) mengaktifkan bit unset terendah (dan tidak ada bit lain). Demikian juga, karena mengurangi 1 dari y matikan semua trailing bit yang tidak disetel dan bit set terendah, y & (y +1) matikan bit set terendah.

Akhirnya, ketika ketidaksetaraan x <y tidak lagi berlaku, <|kembalikan pasangan [x, y] .

Dennis
sumber
0

MATLAB, 67 66 byte

lingkaran:

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

rekursif (67 byte):

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

Pendekatan yang sama untuk mengubah bit seperti banyak jawaban lainnya.

pajonk
sumber
0

Clojure, 63 byte

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

Metode yang sama seperti yang digunakan dalam solusi saya di J.

Pemakaian

=> (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])
mil
sumber