Trao đổi bit với hàng xóm của họ


26

Mô tả công việc

Cho một số nguyên, hoán đổi các bit có ý nghĩa nhỏ nhất (2k của 1)2k -th cho tất cả các số nguyên k> 0 . Đây là trình tự A057300 trong OEIS.

(Số này được giả định là có vô số số 0 hàng đầu. Trong thực tế, điều này chỉ có nghĩa là trả trước một số 0 bit cho các số có độ dài lẻ.)

nhập mô tả hình ảnh ở đây

Đây là , vì vậy mã ngắn nhất (tính bằng byte) sẽ thắng.

Các trường hợp thử nghiệm

0 -> 0
1 -> 2
9 -> 6
85 -> 170
220 -> 236
1827 -> 2835
47525 -> 30298

5
Chúng ta có thể giả sử số phù hợp như một int cho những thứ như bit shift không?
xnor

1
@xnor: Tôi nghĩ đó là sự đồng thuận mặc định / cộng đồng (nếu không câu trả lời trong C, v.v. sẽ luôn luôn sai)? Chắc chắn rồi! :)
Lynn

@Lynn: C yêu cầu unsigned char array_of_bytes[1024]làm việc theo cách bạn mong đợi (tức là một bitfield với CHAR_BITcác mục 1024 * ). Tuy nhiên, tôi tưởng tượng hầu hết các câu trả lời hỗ trợ các đầu vào có độ dài tùy ý sẽ cho CHAR_BITlà chẵn, vì việc dịch chuyển các bit giữa các byte rất cồng kềnh. Vì vậy, bạn hoàn toàn có thể đặt yêu cầu hỗ trợ klên đến một số kích thước không đổi, như 256 hoặc thứ gì đó hợp lý cho AES và các ngôn ngữ không có loại số nguyên 256 bit sẽ phải sử dụng các vòng lặp. Điều đó có thể khiến các vectơ SIMD đáng để xem xét cho câu trả lời x86 asm: P
Peter Cordes

2
Tôi trao đổi @Geobits với Minibits
Trình tối ưu hóa

Câu trả lời:



20

Python 2, 26 byte

lambda n:2*n-3*(4**n/3&n/2)

Thủ thuật bit!

Nói ncó hình thức ...ghfedcbatrong nhị phân. Sau đó, chúng ta có thể chia nó thành từng bit khác như

n   = o + 2*e
n   = ...hgfedcba
o   = ...0g0e0c0a
2*e = ...h0f0d0b0

Sau đó, kết quả chuyển bit scó thể được biểu thị dưới dạng s=2*o+e.

s   = 2*o + e
s   = ...ghefcdab
2*o = ...g0e0c0a0
e   = ...0h0f0d0b

Chúng tôi chỉ muốn tính toán một trong số eovì vậy chúng tôi bày tỏ o=n-2*evà thay thế

s=2*(n-2*e)+e = 2*n-3*e

Vì vậy, bây giờ nó vẫn còn để thể hiện etrong điều khoản n. Số M=4**n/3có dạng ...10101010101nhị phân, đóng vai trò là mặt nạ cho các chữ số lẻ. Số mũ nđảm bảo Mđủ dài. Lấy Bitwise andcủa n/2và giá trị này mang lại cho enhư mong muốn.

n/2     = ...hgfedcb
M       = ...1010101
n/2 & M = ...h0f0d0b = e

Thay vào đó, chúng ta có thể thể hiện edưới dạng o e=(n-o)/2, điều này mang lại s=(n+o*3)/2, giúp tiết kiệm một byte nhờ tối ưu hóa từ xsot.

lambda n:n+(n&4**n/3)*3>>1

Giải thích tuyệt vời, và mẹo hay để sử dụng mặt nạ chỉ một lần bằng cách trừ đi n. Tuy nhiên, tôi thích quy ước đặt tên bit "lẻ" so với "chẵn". LSB là bit 0, là số chẵn (mặc dù đó là bit đầu tiên). Trong lập trình SIMD, nơi các xáo trộn thường chọn các phần tử có chỉ mục, các chỉ số được tính từ 0, do đó, việc coi phần tử thấp là phần tử chẵn là bình thường. ví dụ[ 3 2 1 0 ]
Peter Cordes

Tôi đã thêm một câu trả lời C bằng cách sử dụng biểu thức của bạn. Tất cả tín dụng cho tiết kiệm byte so với câu trả lời C của Digital Trauma là do điều này.
Peter Cordes

2
26:lambda n:n+(n&4**n/3)*3>>1
xsot

@PeterCordes Mã C của bạn hoạt động với tôi với gcc 4.8.3 và cài đặt mặc định. f(x){return x+((x&~0U/3)*3)>>1;}trả về 1 cho đầu vào 2 .
Dennis

@Dennis: Yeah, làm việc cho tôi trong C, xấu của tôi. Tôi thực sự đã thử nghiệm biểu thức trong calc(còn gọi là apcalc), không thực sự C. Tôi nghĩ rằng tôi sẽ ổn vì tôi không cần cắt ngắn đến 32 bit, hoặc bổ sung hai. Tôi không nghĩ rằng biểu hiện có vẻ đúng, vì vậy tôi sẵn sàng tin vào các bài kiểm tra sai của mình. Nhưng dù sao, tôi đang cần một REPL tốt hơn để phát triển các bithacks. Bất kỳ đề xuất? (lý tưởng là dòng lệnh Linux, như bc -lhoặc calc, nhưng thực sự phơi bày int32_t/ uint32_thoặc một cái gì đó, không phải là độ chính xác mở rộng.)
Peter Cordes

10

Hàm C, 38

Xoay vòng một chút:

f(x){return(x&~0U/3*2)/2+(x&~0U/3)*2;}

Ideone.


Hoặc cho niềm vui của nó:

Hàm đệ quy C, 43

Theo công thức OEIS ,a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

f(x){return x>3?4*f(x/4)+f(x%4):x%3?3-x:x;}

hoặc là

f(x){return x>3?4*f(x/4)+f(x%4):x%2*2+x/2;}

Ideone.


1
Sự chuyển đổi thông minh của biểu thức xnor đã giảm xuống còn 32 byte trong C. Tôi đã đăng nó dưới dạng một câu trả lời riêng biệt, vì đó là một cách tiếp cận khác biệt đáng kể.
Peter Cordes

8

CJam, 16 14 13 byte

ri4b4e!2=f=4b

Kiểm tra nó ở đây.

Giải trình

ri  e# Read input and convert to integer.
4b  e# Get base-4 digits.
4e! e# Push all permutations of [0 1 2 3].
2=  e# Select the third one which happens to be [0 2 1 3].
f=  e# For each base-4 digit select the value at that position in the previous
    e# list, which swaps 1s and 2s.
4b  e# Convert back from base 4.

Thủ thuật đó với hoán vị là rất tốt!
Luis Mendo

7

Bình thường, 9 byte

iXjQ4S2)4

Hãy thử nó trong Trình biên dịch Pyth .

Làm thế nào nó hoạt động

  jQ4      Convert the input (Q) to base 4.
 X   S2)   Translate [1, 2] to [2, 1].
i       4  COnvert from base 4 to integer.

5

JavaScript (ES6), 32 30 byte

(n,m=0x55555555)=>n*2&~m|n/2&m

Chỉ hoạt động tối đa 1073741823 do những hạn chế của số nguyên JavaScript. 38 36 byte hoạt động lên tới 4294967295:

(n,m=0x55555555)=>(n*2&~m|n/2&m)>>>0

Chỉnh sửa: Đã lưu 2 byte nhờ @ user81655.

51 byte hoạt động lên tới 4503599627370495:

n=>parseInt(n.toString(4).replace(/1|2/g,n=>3-n),4)

Có thể n<<1n*2gì?
dùng81655

@ user81655 Và tôi cũng có thể sử dụng n/2! Tôi không biết tại sao tôi không nghĩ về những điều đó trước đây.
Neil

Tôi chưa bao giờ thấy >>>... đó là gì?
Tít

@Titus Nó giống như >>>nhưng nó không thay đổi. >>>0về cơ bản chuyển đổi thành một số nguyên không dấu 32 bit.
Neil

5

Hàm x86 asm: 14 byte mã máy

phiên bản uint64_t: 24 byte

x86-64 Quy ước gọi SysV ( xin edi), nhưng cùng mã máy này cũng sẽ hoạt động ở chế độ 32 bit. (Trường hợp ý leachí giải mã là lea eax, [edi + eax*2], cho kết quả giống hệt nhau ).

0000000000000040 <onemask_even>:
  40:   89 f8                   mov    eax,edi
  42:   25 55 55 55 55          and    eax,0x55555555
  47:   29 c7                   sub    edi,eax
  49:   d1 ef                   shr    edi,1
  4b:   8d 04 47                lea    eax,[rdi+rax*2]
  4e:   c3                      ret    
4f: <end>

0x4f - 0x40 = 14 byte

Đây là đầu ra của trình biên dịch từ việc sử dụng ý tưởng mặt nạ xuất sắc của xnor theo cách ngược lại. (Và thuật ngữ ngược lại: bit thấp là bit 0, là số chẵn, không lẻ.)

unsigned onemask_even(unsigned x) {
  unsigned emask = ~0U/3;
  unsigned e = (x & emask);
  return e*2 + ((x - e) >> 1);
}

Tôi không tìm thấy bất kỳ cải tiến nào so với những gì trình biên dịch làm. Tôi có thể đã viết nó là mov eax, 0x555.../ and eax, edi, nhưng đó là cùng một chiều dài.


Hàm tương tự cho số nguyên 64 bit mất 24 byte (xem liên kết godbolt). Tôi không thấy cách nào ngắn hơn 10 byte movabs rax, 0x55...để tạo mặt nạ trong một thanh ghi. ( divHướng dẫn của x86 là khó hiểu, do đó, việc chia 3 người không dấu cho 3 không giúp ích.)

Tôi đã đưa ra một vòng lặp để tạo mặt nạ trong rax, nhưng đó là 10 byte (chính xác là cùng độ dài mov imm64).

# since 0x55 has its low bit set, shifting it out the top of RAX will set CF
0000000000000000 <swap_bitpairs64>:
   0:   31 c0                   xor    eax,eax      ; old garbage in rax could end the loop early
0000000000000002 <swap_bitpairs64.loop>:
   2:   48 c1 e0 08             shl    rax,0x8
   6:   b0 55                   mov    al,0x55      ; set the low byte
   8:   73 f8                   jnc    2 <swap_bitpairs64.loop>  ; loop until CF is set
000000000000000a <swap_bitpairs64.rest_of_function_as_normal>:
 # 10 bytes, same as   mov  rax, 0x5555555555555555
 # rax = 0x5555...
   a:   48 21 f8                and    rax,rdi
   ...

Nếu chúng ta biết rằng không có byte nào trong đó raxcó tập bit thấp, chúng ta có thể bỏ qua xorvà điều này sẽ dài 8 byte.

Một phiên bản trước của câu trả lời này có vòng lặp 10 byte bằng cách sử dụng loopinsn, nhưng nó có thời gian 0xFFFFFFFFFFFFFF08lặp lại trong trường hợp xấu nhất , bởi vì tôi chỉ đặt cl.


5

Oasis , 17 byte (không cạnh tranh)

n4÷axxn4÷xxe+3120

Hãy thử trực tuyến!

Oasis là một ngôn ngữ được thiết kế bởi Adnan chuyên về trình tự.

Hiện tại, ngôn ngữ này có thể làm đệ quy và dạng đóng.

Chúng tôi sử dụng công thức này: a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

Để xác định trường hợp cơ sở là đơn giản: 3120ở cuối chỉ đơn giản có nghĩa là a(0)=0, a(1)=2, a(2)=1, a(3)=3.

n4÷axxn4÷xxe+3120
                0  a(0) = 0
               2   a(1) = 2
              1    a(2) = 1
             3     a(3) = 3

n                  push n (input)
 4÷                integer-divide by 4
   a               a(n/4)
    xx             double twice; multiply by 4
                   now we have 4a(n/4)
      n            push n (input)
       4÷xx        integer-divide by 4 and then multiply by 4
                   since there is no modulo currently, n%4
                   is built as n-(n/4*4)
           e       we should have done a(n-(n/4*4)), but this
                   is a shortcut for a(n-x) where x is the top
                   of stack. Therefore, we now have a(n-n/4*4)
                   which is a(n%4).
            +      add.

4

MATL , 10 byte

BP2eP1ePXB

Hãy thử trực tuyến!

Phiên bản sửa đổi để tạo các điều khoản đầu tiên của chuỗi ( OEIS A057300 ).

Giải trình

B     % Take input implicitly. Convert to binary array
P     % Flip
2e    % Convert to two-row 2D array, padding with a trailing zero if needed. 
      % Because of the previous flip, this really corresponds to a leading zero
P     % Flip each column. This corresponds to swapping the bits
1e    % Reshape into a row
P     % Flip, to undo the initial flipping
XB    % Convert from binary array to number. Display implicitly

3

zsh, 28 byte

<<<$[`tr 12 21<<<$[[#4]$1]`]

Lấy đầu vào làm đối số dòng lệnh, đầu ra trên STDOUT.

Nó không tương thích với Bash vì nó sử dụng cú pháp chuyển đổi cơ sở cụ thể của zsh.

                       $1     input (first command line argument)
                 $[      ]    arithmetic expansion
                   [#4]       output in base 4
              <<<             pass the result of this to...
      tr                      the `tr' command
         12 21                and replace 1s with 2s, 2s with 1s
     `                    `   evaluate the result...
   $[                      ]  in another arithmetic expansion, to convert back
                                to base 10
<<<                           output the result on STDOUT

3

Võng mạc, 70 byte

. +
$ *
+ `(1 +) \ 1
$ 1
x1
1
^
x
r` (.) (.)
$ 2 $ 1
1
x @
+ `@ x
x @@
x * (@ *)
$ .1
0 đô la

Bộ thử nghiệm. (Sửa đổi một chút.)

Chà, chỉ để giải trí thôi: 7 byte

T`12`21

Lấy cơ sở-4 làm đầu vào và đầu ra là cơ sở-4.

Hãy thử trực tuyến!


4
Tôi đang mâu thuẫn. Tôi muốn upvote nửa dưới của câu trả lời của bạn, nhưng downvote nửa trên.
Dennis

1
@Dennis Bây giờ tôi đã đổi các bit đó.
Rò rỉ Nun

3

05AB1E, 8 byte

4B12‡4ö

Cảm ơn @Adnan cho -5 byte!

Sử dụng mã hóa CP-1252.

Dùng thử trực tuyến!

Giải trình:

4B       - Take input and convert to base 4.
  12Â    - Push 12 bifurcated.
     ‡   - Transliterate [1, 2] to [2, 1].
      4ö - Convert to base 10.

2
Đẹp, nhưng bạn có thể thay thế 1 2‚2 1‚bằng 12Â8 byte.
Ad Nam

Câu trả lời tốt đẹp! Đây là một thay thế 8 byte:4в2‰íJJC
Kevin Cruijssen

3

C, 32 30 29 byte

f(x){return(x&~0U/3)*3+x>>1;}                // 30 bit version, see below

// less golfed:
f(x){return ((x & 0x55555555)*3 + x) >>1;}   //  >> is lower precedence than +

Thuật toán được sao chép từ nhận xét của xsot về câu trả lời Python của xnor . Thay vì che dấu cả hai cách, hãy che một cách và kết hợp.

Điều này biên dịch tương tự như phiên bản cuối cùng mà tôi đã thử nghiệm và nó hoạt động (đối với x lên đến 0x3FFFFFFFvà đối với x ở trên miễn là bit 30 không được đặt, xem bên dưới). Trong mã máy, nó có cùng độ dài với câu trả lời asm hiện có của tôi.


Các phiên bản trên luôn xóa bit cao của kết quả . Phiên bản an toàn tốt nhất là 32 byte:

g(x){return 2*x-3*(x/2U&~0U/3);}   // safe 32bit version, works for all x

Phiên bản Python không gặp phải vấn đề này, vì python sử dụng các kiểu số nguyên có độ chính xác tùy ý khi cần , thay vì cắt ngắn đến giới hạn trên cố định.


@Dennis: Argh, vâng, cảm ơn. Tôi đã thực hiện thay đổi cuối cùng đó sau khi thử nghiệm và bỏ lỡ sự khác biệt trong đầu ra asm. Không có gì ngạc nhiên khi tôi nghĩ rằng nó nhìn sai; Tôi đã quên rằng đó >>là ưu tiên thấp. Tôi không chơi golf thường xuyên đủ để nhớ chính xác các quy tắc là gì, vì các cảnh báo của trình biên dịch gợi ý các parens trong các trường hợp nguy hiểm giúp tôi tiết kiệm được mã thực. : P
Peter Cordes

2
Bạn có thể bỏ khoảng trống đó bằng cách sắp xếp lại các thuật ngữ trong biểu thức.
xsot

2

Javascript (ES6), 113 109 byte

Đã lưu 4 byte nhờ Upgoat

n=>+('0b'+/(..)+$/.exec('0'+n.toString`2`)[0].split``.reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])[0],2)

Làm thế nào nó hoạt động

n=>+('0b'+                              //parse as binary literal
    /(..)+$/.exec('0'+n.toString`2`)[0] //convert to binary string with an even number of digits
        .split``                        //convert to array
        .reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])
                                        //swap all numbers
)

sử dụng +('0b"+binary_string_here)thay vì `parseInt (..., 2)
Hạ cấp

1

J, 20 byte

4#.0 2 1 3{~4#.^:_1]

Sử dụng

>> f =: 4#.0 2 1 3{~4#.^:_1]
>> f 85
<< 170

Trong trường hợp >>là STDIN và <<là STDOUT.

Bị đánh cắp

to_base   =: 4 #.^:_1 ]
transpose =: 0 2 1 3 {~ to_base
from_base =: 4 #. transpose

Ba dĩa.

Sidenote

Trong trình thông dịch chính thức, ^:_1có thể được thay thế bằng inv, tiết kiệm 1 byte.

Tuy nhiên, không ai trong số các phiên dịch viên trực tuyến thực hiện điều này.



1

INTERCAL , 60 byte

DOWRITEIN.1PLEASE.1<-!1~#21845'$.1~#43690DOREADOUT.1DOGIVEUP

Hãy thử trực tuyến!

Hoạt động cho các số nguyên 16 bit, với I / O được thực hiện ở định dạng tự nhiên nhất cho INTERCAL: đầu vào là một chuỗi các chữ số thập phân được viết bằng một trong một số ngôn ngữ tự nhiên hoặc được xây dựng và đầu ra là "chữ số La Mã bị đánh cắp".

Đây là một trong những thách thức hiếm hoi mà các nhà khai thác nhị phân của INTERCAL thực sự có thể được sử dụng hoàn toàn bằng trực giác, vì các bit định vị lại là tất cả những gì họ muốn nói. Chọn ( ~) lấy các bit từ đối số đầu tiên của nó tương ứng với các đối số trong đối số thứ hai của nó và đặt chúng sang phải bằng các số 0 và mingle ( $) xen kẽ các bit từ các đối số của nó sao cho các bit từ đối số thứ nhất có ý nghĩa hơn. Vì vậy, giải pháp đơn giản là chọn ra các bit xen kẽ ít quan trọng hơn ( .1~#21845), chọn ra các bit xen kẽ quan trọng hơn (.1~#43690) và xen kẽ chúng lại với nhau theo thứ tự ngược lại. May mắn thay cho số byte, mặc dù các toán tử của INTERCAL không có quyền ưu tiên xác định (vì mục tiêu của ngôn ngữ là không có tiền lệ), nhưng hóa ra C-INTERCAL trên TIO không yêu cầu nhiều nhóm cho biểu thức cụ thể này, chỉ tốn một byte kể từ '.có thể viết tắt !.

Với sự hỗ trợ cho số nguyên 32 bit:

INTERCAL , 67 byte

DOWRITEIN:1PLEASE:1<-':1~#0$#65535'$:1~#65535$#0DOREADOUT:1DOGIVEUP

Hãy thử trực tuyến!

INTERCAL không cho phép các chữ 32 bit, điều này thực sự làm cho việc này dễ đọc hơn một chút , vì điều đó có nghĩa là các hằng số ma thuật để chọn các bit xen kẽ phải được xây dựng bằng cách trộn lẫn hai chữ 16 bit với nhau, trong đó tất cả là số 0 và chữ kia tất cả những người. (Trên thực tế, ngay cả khi có 32 bit, thì nó vẫn ngắn hơn. #0$#65535Tắt hai byte #1431655765và điều tương tự cũng xảy ra với cái kia.) Điều này truyền đạt toàn bộ quá trình một cách không tự nhiên cho INTERCAL.

Một cách tiếp cận khác với việc sử dụng quá tải toán hạng vụng về :

INTERCAL , 71 byte

DO:1<-:1/.2$.3PLEASEWRITEIN:2DO:1<-:2PLEASE:2<-.3$.2DOREADOUT:2DOGIVEUP

Hãy thử trực tuyến!

Điều này không cần phải chọn hoàn toàn bằng cách khai báo :1được .2trộn lẫn .3, cài đặt :1thành đầu vào, sau đó xuất ra .3trộn lẫn với .2. Kể từ khi :1được quá tải như .2$.3, DO :1 <- :2giá trị chuyển nhượng tới .2.3như vậy mà :1mua lại giá trị của :2, mà kết quả trong .2chứa các bit xen kẽ ý nghĩa hơn từ :2.3chứa các bit xen kẽ ít quan trọng. Đây sẽ là ngắn hơn của hai giải pháp 32 bit bằng bốn byte nếu PLEASE WRITE IN :1có thể thay thế PLEASE WRITE IN :2 DO :1 <- :2bằng quá tải :1, nhưngCALCULATINGhóa ra là cần thiết cho việc sử dụng quá tải. Tôi cũng cảm thấy có thể có một số cách ngắn hơn để tự thực hiện quá tải hơn là bắt đầu chương trình DO:1<-:1/.2$.3, nhưng vì đây là INTERCAL nên tôi cũng cảm thấy như không thể có.


0

Toán học, 44 byte

Fold[3#+##&,#~IntegerDigits~4/.{1->2,2->1}]&

Cách tiếp cận tương tự như câu trả lời của tôi về CJam: chuyển đổi sang cơ sở 4, hoán đổi 1 và 2, chuyển đổi trở lại. Nó cũng sử dụng thủ thuật của alephalpha để thay thế FromDigitsbằng một Foldthao tác để tiết kiệm một byte.


0

Trên thực tế, 16 byte

4@¡"21""12"(t4@¿

Hãy thử trực tuyến!

Giải trình:

4@¡"21""12"(t4@¿
4@¡               base 4 representation of n
   "21""12"(t     translate (swap 1s and 2s)
             4@¿  base 4 to decimal

0

J, 22 byte

([:,_2|.\,&0)&.(|.@#:)

Cách tiếp cận khác dựa trên thao tác mảng thay vì thủ thuật cơ sở 4.

Sử dụng

   f =: ([:,_2|.\,&0)&.(|.@#:)
   (,.f"0) 0 1 9 85 220 1827 47525
    0     0
    1     2
    9     6
   85   170
  220   236
 1827  2835
47525 30298

Giải trình

([:,_2|.\,&0)&.(|.@#:)  Input: n
                   #:   Get the value as a list of base 2 digits
                |.@     Reverse it
(           )&.         Apply to the list of base 2 digits
         ,&0            Append a zero to the end of the list
    _2  \               Split the list into nonoverlapping sublists of size 2
      |.                Reverse each sublist
 [:,                    Flatten the list of sublists into a list
             &.(    )   Apply the inverse of (reversed base 2 digits)
                        to convert back to a number and return it

0

REXX, 88 byte

n=x2b(d2x(arg(1)))
o=0
do while n>''
  parse var n a+1 b+1 n
  o=o||b||a
  end
say x2d(b2x(o))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.