ค้นหาศูนย์ที่สอง


10

ท้าทาย

รับค่าจำนวนเต็มในรูปแบบเสริมของ 32- บิตสองส่งกลับดัชนีของเลขศูนย์ที่สำคัญน้อยที่สุดที่สองในการแทนแบบไบนารีซึ่งดัชนีของ0แทนบิตที่สำคัญน้อยที่สุดและดัชนีของ31แทนบิตที่สำคัญที่สุด

หากไม่มีศูนย์ที่สองคุณอาจคืนค่า 0 จำนวนลบค่าเท็จหรือรายงานข้อผิดพลาดด้วยวิธีที่เหมาะสมในภาษาของคุณ

คุณสามารถใช้การจัดทำดัชนี 1 แบบได้หากต้องการ แต่กรณีทดสอบด้านล่างจะใช้การจัดทำดัชนีแบบ 0

คุณอาจใช้จำนวนเต็มไม่ได้ลงนามถ้าคุณต้องการ [0, 2^32)ถ้าคุณทำแล้วคุณจะต้องจัดการกับจำนวนเต็มในช่วง [-2^31, 2^31)ถ้าคุณใช้ลงนามจำนวนเต็มคุณต้องจัดการกับจำนวนเต็มในช่วง กรณีทดสอบที่นี่จะใช้จำนวนเต็มที่ลงนาม แต่โปรดทราบว่า-x(ลงนาม) คือ2^32 - x(ไม่ได้ลงนาม)

กรณีทดสอบ

0 (0b00) -> 1
1 (0b001) -> 2
10 (0b1010) -> 2
11 (0b01011) -> 4
12 (0b1100) -> 1
23 (0b010111) -> 5
-1 (0b11..11) -> ไม่มี
-2 (0b11..10) -> ไม่มี
-4 (0b11..00) -> 1
-5 (0b11..1011) -> ไม่มี
-9 (0b11..10111) -> ไม่มี
2 ^ 31-2 (0b0111 ..1110) -> 31

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

นี่คือดังนั้นคำตอบที่สั้นที่สุดในแต่ละภาษาจะชนะ!


เราสามารถใช้จำนวนเต็มที่ไม่ได้ลงนามแทนได้หรือไม่?
Leun Nun

[0, 2^32)ใช่คุณอาจตราบใดที่คุณจัดการกับจำนวนเต็มในช่วง
musicman523

1
เรารับจำนวนเต็มหรือสตริง0b...เป็นอินพุตหรือไม่
TheLethalCoder

1
@JonathanAllan ฉันเดาไม่ได้เพราะผมได้รับการแก้ไขในคำตอบของวุ้นของฉันด้วยเพราะผมไม่ควรจะกลับมา2^32-1 33
Erik the Outgolfer

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

คำตอบ:


16

Python 2 , 45 ไบต์

lambda n:[i for i in range(32)if n|1<<i>n][1]

ลองออนไลน์!

ใช้การจัดทำดัชนี 0 หมายเลขที่ไม่ได้ลงชื่อและส่งข้อผิดพลาดโดยไม่เป็นศูนย์วินาที

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


5
ยินดีต้อนรับสู่ PPCG! โพสต์แรกที่ดี!
Erik the Outgolfer

ขอบคุณ! ฉันยังใหม่ต่อการเล่นกลที่ Python ดังนั้นฉันจึงดีใจที่รหัสนี้ไม่ได้ถูกนำลงกอล์ฟทันที
Arnold Palmer

เยี่ยมมาก :) แล้ว n = 2147483647 ล่ะ
mdahmoune

@mdahmoune 2 ** 31-1 ควรเกิดข้อผิดพลาดเนื่องจากการแสดงเลขฐานสองใน 32 บิตคือ 0b0111111111111111111111111111111111111111 ซึ่งไม่มีวินาทีที่สองเว้นแต่ว่าฉันจะพลาดบางสิ่งบางอย่าง ...
Arnold Palmer

6

JavaScript (ES6), 34 ไบต์

ส่งคืนดัชนีตาม 0 หรือ-1หากไม่พบศูนย์ที่สอง

n=>31-Math.clz32((n=~n^~n&-~n)&-n)

กรณีทดสอบ

นิพจน์ทางเลือก

n=>31-Math.clz32((n=~n^++n&-n)&-n)

เวอร์ชันแบบเรียกซ้ำ 42 ไบต์

ส่งคืนดัชนีตาม 0 หรือfalseหากไม่พบศูนย์ที่สอง

f=(n,p=k=0)=>n&1||!k++?p<32&&f(n>>1,p+1):p

อย่างไร?

f=(n,p=k=0)=>                               // given n, p, k
             n&1||                          // if the least significant bit of n is set
                  !k++?                     // or this is the 1st zero (k was not set):
                       p<31&&               //   return false if p is >= 31
                             f(n>>1,p+1)    //   or do a recursive call with n>>1 / p+1
                                        :p  // else: return p

กรณีทดสอบ

รุ่นสำรองที่แนะนำโดย Neil ขนาด 41 ไบต์

ส่งคืนดัชนีแบบอิง 0 หรือส่งข้อผิดพลาดการเรียกซ้ำมากเกินไปหากไม่พบศูนย์ที่สอง

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)

รุ่นเรียกซ้ำ 41 ไบต์:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil

5

เยลลี่ขนาด 7 ไบต์

|‘‘&~l2

ลองออนไลน์!

มันให้ผลลัพธ์ที่ไม่อยู่ในช่วง [1,31] หากไม่มีศูนย์ที่สอง ซึ่งรวมถึงการและ32 33 (-inf+nanj)ฉันเดาว่ามันสมเหตุสมผล

log(((x|(x+1))+1)&~x)/log(2)มันจะคำนวณ


1
-inf+nanjฉันไม่คิดว่าจะมีอยู่
Luis Mendo

มันไม่ได้ส่งออก(-inf+nanj)สำหรับการป้อนข้อมูล2147483647ที่มีการเป็นตัวแทนไบนารีของ 31 1s จึงไม่มีศูนย์ที่สองในสัญกรณ์ที่ลงนาม 32- บิต (นี่คือเหตุผลที่มันสั้นกว่าคำตอบของฉันและ Erik มาก)
Jonathan Allan

จริงๆแล้วมันผลิตเมื่อไหร่(-inf+nanj) ?
Jonathan Allan

... อ่าฉันคิดว่ามันใช้ได้แล้วคุณกำลังใช้ตัวเลือกที่เซ็นชื่อใช่ไหม
Jonathan Allan

4

Java, ... 194 191 186 ไบต์

static int f(int n){char[] c=Integer.toBinaryString(n).toCharArray();int j=0,o=2^32-2,i=c.length,l=i-1;if(n<0|n>o)return 0;for(;j<2&i>0;j+=c[--i]==48?1:0);if(j==2)return l-i;return 0;}

-159 ไบต์สำหรับการใช้ชื่อตัวแปรที่มีขนาดเล็กและลบช่องว่าง
-25 ไบต์หลังจากการตัวแปรแม้สั้นและขอบคุณที่เคล็ดลับ @KevinCruijssen
-18 Bytes, ช่องว่างมากขึ้นชื่อฟังก์ชัน
-3 ไบต์ขอบคุณ @KevinCruijssen สั้นลงถ้าเงื่อนไข
-5 ไบต์ ขอขอบคุณ @Arnold Palmer @KevinCruijssen ทำให้การตัดทอนวนสั้นลง

Ungolfed

public static int getPosSecondZero2(int number){
    int overflow = 2^32-2;
    if(number < 0 || number > overflow){
        return 0;
    }    
    String binaryString = Integer.toBinaryString(number);   
    char[] binaryCharArray = binaryString.toCharArray();    
    int count = 0;
    int idx = binaryCharArray.length;
    int length = binaryCharArray.length -1;
    while(count < 2 && idx>0){
        idx--;
        if(binaryCharArray[idx] == '0'){
            count++;
        }   
    }
    if(count == 2)
        return length-idx;
    return 0;
}

ยินดีต้อนรับสู่ PPCG! มีบางสิ่งที่คุณสามารถตีกอล์ฟได้: static สามารถลบออกได้ if(n<0||n>o){return 0;}สามารถif(n<0|n>o)return 0;( |แทน||และไม่มีวงเล็บ); bs, bsaและอื่น ๆ ทั้งหมดสามารถเป็นอักขระเดียว (ไม่เคยใช้ชื่อตัวแปร / วิธีหลายไบต์ในโค้ดกอล์ฟ); คุณสามารถรวมints int o=2^32-2,c=0,i=x.length,l=i-1;เช่นนี้ และยังมีอีกหลายสิ่งที่ต้องตีกอล์ฟ เคล็ดลับสำหรับการเล่นกอล์ฟใน Javaและเคล็ดลับสำหรับการเล่นกอล์ฟในทุกภาษาอาจเป็นที่น่าสนใจในการอ่าน ยินดีต้อนรับอีกครั้งและสนุกกับการเข้าพักของคุณ! :)
Kevin Cruijssen

ฉันคิดว่ายังมีช่องว่างสองสามอย่างที่คุณสามารถลบได้ในการประกาศตัวแปรของคุณ ยินดีต้อนรับ! :)
musicman523

@ musicman523 ขอบคุณใช่แก้ไขแล้ว 194 สำหรับตอนนี้ :)
0x45

1
if(c[i]=='0'){j++;}ยังคงสามารถ golfed ถึงif(c[i]==48)j++;-3 ไบต์ :) แก้ไข: หรือดีกว่ายัง: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}สามารถfor(;j<2&i>0;j+=c[i--]==48?1:0);สำหรับ -8 ไบต์
Kevin Cruijssen

1
@ 0x45 ฉันเชื่อว่าถ้าคุณเปลี่ยนรหัสของ @ KevinCruijssen ให้for(;j<2&i>0;j+=c[--i]==48?1:0);ทำงานได้ ข้อผิดพลาดมาจากiความยาวของสตริงดังนั้นเริ่มแรกคุณพยายามทำดัชนีผ่านขอบเขตของอาร์เรย์ หากคุณทำการลดค่าลงล่วงหน้า (ดังที่แสดงในตัวอย่างข้อมูลที่อัปเดตแล้ว) ครั้งแรกที่คุณใช้รหัสจะเข้าถึงได้c[c.length-1]เหมือนในรหัสต้นฉบับ
Arnold Palmer


3

รหัสเครื่อง IA-32 ขนาด14 13 ไบต์

hexdump:

F7 D1 0F BC C1 0F B3 C1 0F BC C9 91 C3

รายการถอด:

0:  f7 d1                   not    ecx
2:  0f bc c1                bsf    eax,ecx
5:  0f b3 c1                btr    ecx,eax
8:  0f bc c1                bsf    ecx,ecx
b:  91                      xchg   eax, ecx
c:  c3                      ret

ได้รับข้อมูลในecx; เอาท์พุทเป็นalระบบ ส่งคืน 0 เนื่องจากข้อผิดพลาด

ก่อนอื่นมันกลับค่าอินพุตดังนั้นจึงสามารถใช้คำแนะนำการสแกนบิตเพื่อค้นหาบิตที่ตั้งไว้ มันค้นหาบิตเซ็ตที่สำคัญน้อยที่สุดรีเซ็ตมันค้นหาบิตเซ็ตสำคัญน้อยที่สุดอีกครั้งและส่งคืนผลลัพธ์

หากคำแนะนำในการสแกนบิตไม่พบบิตที่ตั้งไว้เอกสารของ Intel บอกว่าเอาท์พุทไม่ได้กำหนด อย่างไรก็ตามในทางปฏิบัติตัวประมวลผลทั้งหมดออกจากการลงทะเบียนปลายทางไม่เปลี่ยนแปลงในกรณีนี้ (ตามที่ระบุไว้โดย Cody Gray เอกสารของ AMD อธิบายถึงพฤติกรรมนี้ว่าเป็นสิ่งที่จำเป็น)

ดังนั้นมีกรณีต่อไปนี้:

  1. ไม่มีศูนย์บิต (ไบนารี 111 ... 1): ecx ถูกตั้งค่าเป็น 0 notและยังคงเป็น 0
  2. หนึ่งศูนย์บิต: ecx ถูกตั้งค่าเป็น 0 btrและยังคงเป็น 0 หลังจากนั้นbsf
  3. สองศูนย์บิต: ecx ตั้งค่าที่เหมาะสมโดย bsf

มันเป็นเพียงเอกสารของ Intel ที่ระบุว่าการสแกนบิตบน 0 ไม่ได้ถูกกำหนด เอกสารของเอเอ็มดีระบุว่าเอกสารปลายทางไม่เปลี่ยนแปลง หากคุณต้องการหลีกเลี่ยงพฤติกรรมนี้โดยปกติคุณจะต้องเพิ่มคำนำหน้า REP เพื่อรับ LZCNT หรือ TZCNT อย่างใดอย่างหนึ่ง แต่นั่นจะเป็นการเพิ่มจำนวนไบต์ซึ่งเป็นสิ่งที่ไม่พึงประสงค์สำหรับการเล่นกอล์ฟตามปกติ
โคดี้เกรย์

1
คุณทำงานหนักเกินไปจริงๆที่นี่ ความท้าทายไม่ต้องการให้คุณแยกแยะระหว่างกรณีที่ไม่มีศูนย์บิตและกรณีที่มีเพียง 1 ศูนย์บิต อนุญาตให้คุณส่งคืน 0 (หรือค่าลบใด ๆ ) ในทั้งสองกรณี ดังนั้นถึงแม้ว่า 1-byte SALC+ DECจะฉลาดมากแต่คุณสามารถกำจัด byte โดยใช้สิ่งที่อยู่ในคำสั่งECXที่สอง BSFสิ่งเดียวที่ต้องมีคือ 1 ไบต์XCHGเพื่อให้ได้ผลลัพธ์EAXดังนั้นจึงสามารถส่งคืนได้ ในคำอื่น ๆnot ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
โคสีเทา

1
นี่คือการเชื่อมโยง "ลองออนไลน์" สำหรับการดังกล่าวข้างต้น เนื่องจากคุณใช้ECXเป็นทะเบียนการป้อนข้อมูลเราจำเป็นต้องแจ้งให้ GCC ใช้การประชุมการโทรด่วน
โคดี้เกรย์

2

Dyalog APL ขนาด 20 ไบต์

{2⊃(⍳32)/⍨~⌽⍵⊤⍨32⍴2}

ใช้การจัดทำดัชนี 1 ครั้งโดยส่งINDEX ERRORในกรณีที่ไม่มีศูนย์วินาที

อย่างไร?

⍵⊤⍨- เข้ารหัสเป็น

32⍴2 - สตริงไบนารีความยาว 32

- ย้อนกลับ

~ - ปฏิเสธ (0 → 1, 1 → 0)

(⍳32)/⍨ - บีบอัดด้วยช่วง 1-32 (ปล่อยดัชนีเป็นศูนย์)

2⊃ - เลือกองค์ประกอบที่สอง


คุณสามารถบันทึกไบต์จำนวนมากโดยใช้ Where ( )
TwiNight

@TwiNight ฉันใช้ dyalog 14
Uriel

TIO มี Dyalog 16 หากคุณต้องการ
TwiNight

1

เยลลี่ 13 ไบต์

B¬Ṛ;1,1ḣ32TḊḢ

ลองออนไลน์!

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


เอาต์พุตนี้33สำหรับอินพุต4294967295( 2^32-1ซึ่งเทียบเท่ากับแบบไม่ลงนาม 32 บิต-1)
musicman523

@ musicman523 อืมมีบางอย่างมีกลิ่นคาว ...
Erik the Outgolfer

1

เยลลี่ 12 ไบต์

,4BUFḣ32¬TḊḢ

ลิงก์ monadic รับจำนวนเต็มโดยใช้ตัวเลือกที่ไม่ได้ลงชื่อและส่งคืนผลลัพธ์ 1 ดัชนี (ส่งคืน 0 เมื่อไม่มีอยู่)

ลองออนไลน์!

หรือ

32Ḷ2*|€n⁸TḊḢ

ลองดู

อย่างไร?

1

,4BUFḣ32¬TḊḢ - Link: number, n   e.g. 14
,4           - pair with 4            [14,4]
  B          - to binary              [[1,1,1,0],[1,0,0]]
   U         - upend                  [[0,1,1,1],[0,0,1]]
    F        - flatten                [0,1,1,1,0,0,1]
     ḣ32     - head to 32             [0,1,1,1,0,0,1] (truncates the right if need be)
        ¬    - not (vectorises)       [1,0,0,0,1,1,0]
         T   - truthy indexes         [1,5,6]
          Ḋ  - dequeue                [5,6]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

2

32Ḷ2*|€n⁸TḊḢ - Link: number, n   e.g. 14
32Ḷ          - lowered range of 32    [ 0, 1, 2, 3, 4, 5, ...,31]
   2*        - 2 exponentiated        [ 1, 2, 4, 8,16,32, ...,2147483648]
     |€      - bitwise or for €ach    [15,14,14,14,30,46, ...,2147483662]
        ⁸    - chain's right argument 14
       n     - not equal?             [ 1, 0, 0, 0, 1, 1, ..., 1]
         T   - truthy indexes         [ 1, 5, 6, ..., 32]
          Ḋ  - dequeue                [ 5, 6, ..., 32]
           Ḣ - head                   5
             -   if the dequeued list is empty the head yields 0

1

รหัสเครื่อง x86_64 ขนาด34 32 ไบต์

ไม่แน่ใจว่านี่เป็นวิธีที่ถูกต้องหรือไม่ไบต์ค่อนข้างมาก (กลับกลายเป็นว่าไม่ได้ ):

31 c0 83 c9 ff 89 fa 83 e2 01 83 f2 01 01 d1 7f 09 ff c0 d1 ef eb ee 83 c8 ff 83 f8 1f 7f f8 c3

ลองออนไลน์!

second_zero:
  # Set eax = 0
  xor  %eax, %eax
  # Set ecx = -1
  xor %ecx,%ecx
  not %ecx

  # Loop over all bits
Loop:
  # Get current bit
  mov %edi, %edx
  and $0x1, %edx
  # Check if it's zero and possibly increment ecx
  xor $0x1, %edx
  add %edx, %ecx
  # If ecx > 0: we found the position & return
  jg Return
  # Increment the position
  inc %eax
  # Shift the input and loop
  shr %edi
  jmp Loop

Fix:
  # If there's not two 0, set value to -1
  xor %eax,%eax
  not %eax

Return:
  # Nasty fix: if position > 31 (e.g for -1 == 0b11..11)
  cmp $31, %eax
  jg  Fix

  ret

ขอบคุณ @CodyGray สำหรับ-2ไบต์


1
การวนซ้ำทุกบิตอาจไม่ใช่วิธีที่ถูกต้องไม่ว่าจะเป็นการเล่นโค๊ดหรือในโลกแห่งความเป็นจริง ความก้าวหน้าที่แท้จริงจะใช้หนึ่งในคำแนะนำที่ช่วยให้คุณสามารถจัดการทั้งหมด 32 (หรือ 64) บิตในครั้งเดียวเช่นBSF, BSR, POPCNT, BTฯลฯ Anatolyg ได้ส่งวิธีการแก้ปัญหาตามบรรทัดเหล่านี้ ฉันยังไม่ได้ตัดสินใจว่าจะสามารถเอาชนะได้ :-p
Cody Gray

1
โดยวิธีการเคล็ดลับการเล่นกอล์ฟที่มีประโยชน์ในการตั้งค่าการลงทะเบียนเพื่อ -1 คือการ OR ด้วย -1 ตัวอย่างเช่นor ecx, -1. นั่นคือ 3 ไบต์, 1 ไบต์สั้นกว่า XOR + NEG นี่ไม่ใช่เคล็ดลับที่ดีเมื่อไม่เล่นกอล์ฟเพราะจะแนะนำการอ่านที่ผิดพลาดในการลงทะเบียนปลายทาง แต่มีเพียงคุณใช้mov ecx, -1และใช้เวลา 5 ไบต์
โคดี้เกรย์

1

8th , 149 ไบต์

2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@

รหัสความคิดเห็น

: f \ n -- a1 a2 n 

  \ decimal to binary conversion
  2 base swap >s nip decimal     

  \ 32bit formatting (padding with 0)            
  s:len 32 swap n:- ( "0" s:<+ ) swap times  

  \ put reversed binary number into an array 
  s:rev null s:/

  \ build a new array with position of each zero 
  a:new swap ( "0" s:= if a:push else drop then ) a:each

  \ put on TOS the position of the 2nd least least-significant zero digit
  swap 1 a:@
;

การใช้งานและเอาท์พุท

ok> : f 2 base swap >s nip decimal s:len 32 swap n:- ( "0" s:<+ ) swap times s:rev null s:/ a:new swap ( "0" s:= if a:push else drop then ) a:each swap 1 a:@ ;

ok> [0, 1, 10, 11, 12, 23, -1, -2, -4, -5, -9, 2147483646]

ok> ( dup . " -> " .  f . 2drop cr ) a:each
0 -> 1
1 -> 2
10 -> 2
11 -> 4
12 -> 1
23 -> 5
-1 -> null
-2 -> null
-4 -> 1
-5 -> null
-9 -> null
2147483646 -> 31

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