ตัวเลขต่างกันน้ำหนักเดียวกัน


22

พื้นหลัง

น้ำหนัก Hammingของจำนวนเต็มคือจำนวนของคนในการเป็นตัวแทนไบนารี สำหรับความท้าทายนี้จำนวนเต็มจะถูกแทนด้วย 32 บิตและไม่ได้ลงนาม

ท้าทาย

กำหนดจำนวนเต็มตั้งแต่ 0 ถึง 2 ^ 32-1 (ไม่รวม) ส่งออกจำนวนเต็มที่แตกต่างกันในช่วงเดียวกันและยังมีน้ำหนัก Hamming เดียวกัน

ตัวอย่าง

Input (Decimal) | Input (Binary) | Hamming weight | Possible output (Decimal)
       46       |   0b0010 1110  |       4        |      15
       12       |   0b0000 1100  |       2        |      3
        1       |   0b0000 0001  |       1        |      2
        3       |   0b0000 0011  |       2        |      6
      2^31      |   0b1000....0  |       1        |      1
      2^31+2    |   0b1000...10  |       2        |      3
      2^32-5    |   0b1111..011  |       31       |      2^31-1
      2^32-2    |   0b1111....0  |       31       |      2^31-1
        0       |   0b0000 0000  |       0        | None (This case need not be handled)
      2^32-1    |   0b1111....1  |       32       | None (This case need not be handled)

เกณฑ์การให้คะแนน

นี่คือดังนั้นการแก้ปัญหาในจำนวนไบต์น้อยที่สุดในแต่ละภาษาชนะ


2
ฉันขอแนะนำให้เพิ่มตัวเลขคี่ระหว่าง 2 ^ 31 + 1 และ 2 ^ 32-3 เนื่องจากคำตอบบางข้อนั้นล้มเหลว
Ørjan Johansen


เมื่อคุณเพิ่งเพิ่ม2^31+2ฉันจะทำซ้ำที่ฉันพูดจำนวนคี่ คำตอบในคำถามล้มเหลวก็ต่อเมื่อทั้งบิตสูงสุดและบิตต่ำสุด1เท่านั้น
Ørjan Johansen

ฉันโง่. ขอขอบคุณ. จะแก้ไขนั่น
musicman523

1
@ musicman523 ฉันเพิ่งจะค้นคำถามที่ใช้งานอยู่และเห็นคำถามนี้ และสังเกตว่าคุณยังไม่ได้เพิ่มกรณีทดสอบตามที่ร้องขอ
Draco18s

คำตอบ:


29

ชุดประกอบ x86-64, 5 4 ไบต์

   0:   97                      xchg   %eax,%edi
   1:   d1 c0                   rol    %eax
   3:   c3                      retq   

ฟังก์ชั่นที่ใช้หลักการเรียก C ที่ค่าบิตทวนการหมุนอาร์กิวเมนต์ของมันซ้าย 1 บิต


Dammit - ฉันกำลังจะโพสต์สิ่งนี้ - ทำได้ดีมาก :)
Digital Trauma

12
ชุดเต้น Jelly: o
Uriel

นี่ไม่ใช่การคูณด้วย 2 ใช่ไหม ถ้าเป็นเช่นนั้น 2 ไบต์
Pyth

@ NoOneIsHere ไม่นี่ไม่ใช่การคูณด้วย 2 การคูณ 2 ส่งครึ่งหนึ่งของอินพุตนอกช่วงที่ต้องการและถ้าคุณไม่สนใจบิตโอเวอร์โฟลว์ทางซ้ายคุณลดน้ำหนักแฮมมิงค์ลง 1 นี่คือบิต การหมุนซึ่งจะนำบิตการโอเวอร์โฟลกลับมาจากทางขวา
Anders Kaseorg

1
@DigitalTrauma GCC 4.9.0 และต่อมาก็ฉลาดพอที่จะรวบรวมn << 1 | n >> 31เข้าไปrolแทนror(ประหยัดไบต์)
Anders Kaseorg



6

เยลลี่ , 10 8 ไบต์

‘&~^^N&$

สลับชุดที่มีนัยสำคัญน้อยที่สุดและบิต unset

ลองออนไลน์!

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

‘&~^^N&$  Main link. Argument: n

‘         Increment; yield n+1, toggling all trailing set bits and the rightmost
          unset bit.
  ~       Bitwise NOT; yield ~n, toggling ALL bits of n.
 &        Bitwise AND; yield (n+1)&~n, keeping the only bit that differs in n+1 and
          ~n, i.e., the rightmost unset bit.
   ^      Perform bitwise XOR with n, toggling the rightmost unset bit.
       $  Combine the two links to the left into a monadic chain.
     N        Negate; yield -n. Since ~n = -(n+1) in 2's complement, -n = ~n+1.
      &       Take the bitwise AND of n and -n. Since -n = ~n + 1 and n = ~~n, the
              same reasoning that applied for (n+1)&~n applies to -n&n; it yields
              the rightmost unset bit of ~n, i.e., the rightmost set bit of n.
    ^      XOR the result to the left with the result to the right, toggling the
           rightmost set bit of the left one.

5

JavaScript (ES6), 35 31 ไบต์

ค้นหาการเปลี่ยนบิตแรก (0 → 1 หรือ 1 → 0) และสลับกลับ

f=(n,k=3)=>(n&k)%k?n^k:f(n,k*2)

การสาธิต

การหมุนบิต 14 ไบต์

สั้นลง แต่สนุกน้อยกว่ามาก

n=>n>>>31|n<<1

การสาธิต


ตัวดำเนินการ bitwise JavaScript ให้จำนวนเต็มที่ลงนาม 32- บิตมากกว่าที่ไม่ได้ลงนาม ยกตัวอย่างเช่นf(2147483647)เป็น-1073741825และเป็น(n=>n>>>31|n<<1)(2147483647) -2
Anders Kaseorg

2
มันใช้ได้ดีตราบใดที่มีไม่เกิน 32 บิต
musicman523

คุณสามารถเพิ่มคำอธิบายสำหรับคำแรกได้หรือไม่? ฉันพยายามที่จะเรียนรู้จาวาสคริปต์และเป็นความสูญเสียที่เป็นวิธีการโทร f กับ k ไม่ได้กำหนดและยังได้รับคำตอบที่สมเหตุสมผล!
musicman523

2
@ musicman523 ที่นี่คือเคล็ดลับที่เกี่ยวข้อง โดยทั่วไปkเป็นชุดแรกไปundefinedและเราจะใช้ประโยชน์จากความจริงที่ว่าเท่ากับ~undefined -1
Arnauld

@ musicman523 (ฉันไม่ได้ใช้เคล็ดลับนี้อีกต่อไปในรุ่นที่ปรับปรุงแล้ว แต่อย่าลังเลที่จะถามว่าคุณมีคำถามอื่น ๆ เกี่ยวกับคำตอบเดิมหรือไม่)
Arnauld

4

Brain-Flakขนาด 78 ไบต์

(([()()])[[]()]){((){}<({({})({}())}{})>)}{}([(({}(({}){})())<>)]){({}())<>}{}

ลองออนไลน์!

ส่งกลับ 2n ถ้า n <2 ^ 31 และ 2n + 1-2 ^ 32 เป็นอย่างอื่น น่าเสียดายเนื่องจาก Brain-Flak ไม่มีวิธีที่รวดเร็วในการตรวจสอบเครื่องหมายของตัวเลขโปรแกรมหมดเวลากับ TIO หากอินพุตแตกต่างจาก 2 ^ 31 มากกว่า 500,000 ประมาณ

คำอธิบาย

ก่อนอื่นกด -2 ^ 32 ลงในสแต็ก:

(([()()])[[]()])                               push (initial value) -2 and (iterator) -5
                {((){}<                >)}     do 5 times:
                       ({({})({}())}{})        replace the current (negative) value with the negation of its square
                                            {}   pop the (now zero) iterator

จากนั้นคำนวณผลลัพธ์ที่ต้องการ:

      (({}){})                        replace n by 2n on left stack
   ({}        ())                     push 2n+1-2^32 on left stack
  (              <>)                  push again on right stack
([                  ])                push its negation on right stack
                      {({}())<>}      add 1 to the top value of each stack until one of them reaches zero
                                {}    pop this zero, and implicitly print the number below it on the stack

3

dc, 10

?2~z31^*+p

ลองมันออนไลน์

นี่คือการดำเนินการทางคณิตศาสตร์ของการหมุนขวา 32 บิต:

?           # input
 2~         # divmod by 2 - quotient pushed first, then the remainder
   z        # z pushes the size of the stack which will be 2 (quotient and remainder) ...
    31^     #  ... and take that 2 to the 31st power
       *    # multiply the remainder by 2^31
        +   # add
         p  # output

3

Java 8, 117 17 29 ไบต์

n->n*2%~-(long)Math.pow(2,32)

+12 ไบต์โดยเปลี่ยนintเป็นlongเพราะintขนาดสูงสุดคือ2³¹-1

บันทึก100 89 ไบต์โดยการสร้างพอร์ต @AndersKaseorg 's คำตอบงูใหญ่ที่น่าตื่นตาตื่นใจ

ลองที่นี่

ขาออก:

46 (101110):                                     92 (1011100)
12 (1100):                                       24 (11000)
1 (1):                                           2 (10)
3 (11):                                          6 (110)
10000 (10011100010000):                          20000 (100111000100000)
987654 (11110001001000000110):                   1975308 (111100010010000001100)
2147483648 (10000000000000000000000000000000):   1 (1)
4294967294 (11111111111111111111111111111110):   4294967293 (11111111111111111111111111111101)

คำตอบเก่า ( 117 118 ไบต์):

n->{long r=0;for(;!n.toBinaryString(++r).replace("0","").equals(n.toBinaryString(n).replace("0",""))|r==n;);return r;}

+1 byte โดยเปลี่ยนintเป็นlongเนื่องจากintขนาดสูงสุดคือ2³¹-1

ลองที่นี่

ขาออก:

46 (101110):                                     15 (1111)
12 (1100):                                       3 (11)
1 (1):                                           2 (10)
3 (11):                                          5 (101)
10000 (10011100010000):                          31 (11111)
987654 (11110001001000000110):                   255 (11111111)
2147483648 (10000000000000000000000000000000):   1 (1)

2

Mathematica, 29 ไบต์

Mod@##+Quotient@##&[2#,2^32]&

ลองที่กล่อง Wolfram

หมุนซ้าย arithmetically: ครั้งแรกคูณด้วย 2 ซึ่งอาจจะกะจำนวนออกจากช่วงแล้วตัดออกหลักของช่วงที่มีและเพิ่มกลับด้านขวาด้วยMod[...,2^32]+Quotient[...,2^32]

(Mathematica มี builtin เพียงตัวเดียวที่ให้โมดูลัสและผลหารในครั้งเดียว แต่มันQuotientRemainderเป็นบิตของแต้มต่อกอล์ฟ…)


Mod 2 ^ 32-1 (อีก 4 ไป)
user202729



1

R, 42 63 ไบต์

function(x){s=x;while(s==x){sample(binaryLogic::as.binary(x))}}

สับบิตโดยการสุ่ม แต่ตรวจสอบเพื่อให้แน่ใจว่าไม่ได้ส่งกลับหมายเลขเดิมโดยบังเอิญ


1

ช่องว่าง , 81 80 ไบต์

(บันทึก 1 ไบต์ต้องขอบคุณ @ Ørjan Johansen เตือนฉันซ้ำว่าสั้นกว่าพุช 0)

   
 
 	
					 
    	 
	 		
	 
   	        
 
 	  
 
 	  
	   
  
   	 
	 	 	
 	

ลองออนไลน์!

โดยทั่วไปจะใช้บิตการเลื่อนที่เป็นวงกลมโดยใช้เลขคณิตจำนวนเต็ม การผลักค่าคงที่ที่มีขนาดใหญ่นั้นมีราคาแพงในช่องว่างดังนั้นเราจึงประหยัดไบต์ได้โดยการกด 2 ^ 8 แล้วยกกำลังสองสองครั้ง (บันทึกมากกว่า 1 ไบต์ (2 ^ 16) ^ 2 และ 10 ไบต์กด 2 ^ 32 โดยตรง)

คำอธิบาย

sssn  ; push 0
sns   ; dup
tntt  ; getnum from stdio
ttt   ; retrieve n from heap and put it on the stack
sns   ; dup
ssstsn ; push 2
tstt  ; mod - check if divisible by 2 (i.e. even)
ntsn  ; jez "even"
ssstssssssssn ; push 2^8
sns   ; dup
tssn  ; mul - square it to get 2^16
sns   ; dup
tssn  ; mul - square it to get 2^32
tsss  ; add 2^32 so MSB ends up set after the divide
nssn  ; even:
ssstsn ; push 2
tsts  ; divide by 2, aka shift right
tnst  ; putnum - display result

1
ฉันคิดว่าคุณสามารถแทนที่ที่สองpush 0ด้วยdupคำสั่งเดียวก่อนหน้านี้
Ørjan Johansen

คุณพูดถูกฉันเพิ่งเพิ่มทางลัดไปยัง transpiler ของฉันดังนั้นฉันจึงใช้มันมากเกินไป ...
Ephphatha

0

Python 2.7, 89 ไบต์

โปรแกรมเต็มรูปแบบ:

from random import*;a=list(bin(input())[2:].zfill(32));shuffle(a);print int(''.join(a),2)

ลองออนไลน์!

ยินดีต้อนรับข้อเสนอแนะ! :)


ที่ไม่ถูกต้องเพราะมันสามารถกลับมาหมายเลขเดียวกันโดยบังเอิญ
Ørjan Johansen





โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.