Temukan Nol Kedua

10

Tantangan

Diberikan bilangan bulat dalam format komplemen 32-bit dua , kembalikan indeks digit nol paling signifikan kedua di representasi biner, di mana indeks 0mewakili bit paling signifikan, dan indeks 31mewakili bit paling signifikan.

Jika tidak ada nol kedua, Anda dapat mengembalikan 0, angka negatif, nilai palsu, atau melaporkan kesalahan dengan cara yang masuk akal dalam bahasa Anda.

Anda dapat menggunakan pengindeksan 1 jika Anda mau, tetapi kasus uji di bawah ini akan menggunakan pengindeksan 0.

Anda dapat menggunakan bilangan bulat yang tidak ditandatangani jika Anda menginginkannya; jika Anda melakukannya, maka Anda harus menangani bilangan bulat dalam jangkauan [0, 2^32). Jika Anda menggunakan bilangan bulat yang ditandatangani, Anda harus menangani bilangan bulat di dalam rentang [-2^31, 2^31). Kasing uji di sini akan menggunakan bilangan bulat yang ditandatangani, tetapi perhatikan bahwa -x(ditandatangani) adalah 2^32 - x(tidak ditandatangani).

Uji Kasus

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

Mencetak gol

Ini , jadi jawaban tersingkat di setiap bahasa menang!

musicman523
sumber
Bisakah kita menggunakan integer yang tidak ditandatangani?
Leaky Nun
Ya Anda bisa, selama Anda kemudian menangani bilangan bulat dalam kisaran [0, 2^32).
musicman523
1
Apakah kita mengambil integer atau string 0b...sebagai input?
TheLethalCoder
1
@Jonathan Allan Saya kira tidak, karena saya dikoreksi dengan jawaban Jelly saya 2^32-1karena saya tidak seharusnya kembali 33.
Erik the Outgolfer
1
Jawaban @JonathanAllan Erik benar. Saya telah memperbarui spec tantangan untuk mencerminkan bahwa Anda harus menangani bilangan bulat 32-bit apakah Anda memilih untuk mengambilnya sebagai ditandatangani atau tidak
musicman523

Jawaban:

16

Python 2 , 45 byte

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

Cobalah online!

Menggunakan pengindeksan 0, angka yang tidak ditandatangani, dan melempar kesalahan tanpa nol detik.

Cukup buat daftar indeks bit yang tidak disetel, dari terendah ke tertinggi, dan mengembalikan entri kedua.

Arnold Palmer
sumber
5
Selamat datang di PPCG! Posting pertama yang bagus!
Erik the Outgolfer
Terima kasih! Saya masih benar-benar baru dalam tipu golf dengan Python, jadi saya senang kode ini tidak segera diturunkan.
Arnold Palmer
Hebat :) bagaimana dengan n = 2147483647?
mdahmoune
@mdahmoune 2 ** 31-1 harus error karena representasi binernya dalam 32 bit adalah 0b0111111111111111111111111111111111, yang tidak memiliki detik 0. Kecuali saya kehilangan sesuatu ...
Arnold Palmer
6

JavaScript (ES6), 34 byte

Mengembalikan indeks berbasis 0, atau -1jika tidak ada nol kedua ditemukan.

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

Uji kasus

Ekspresi alternatif

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

Versi rekursif, 42 byte

Mengembalikan indeks berbasis 0, atau falsejika tidak ada nol kedua ditemukan.

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

Bagaimana?

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

Uji kasus

Versi alternatif disarankan oleh Neil, 41 byte

Mengembalikan indeks berbasis 0, atau melempar kesalahan rekursi terlalu banyak jika tidak ada nol kedua ditemukan.

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Arnauld
sumber
Versi rekursif 41-byte:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil
5

Jelly , 7 byte

|‘‘&~l2

Cobalah online!

Ini menghasilkan sesuatu yang tidak dalam kisaran [1,31] jika tidak ada nol kedua. Ini termasuk 32 33dan (-inf+nanj). Saya kira itu masuk akal.

Itu menghitung log(((x|(x+1))+1)&~x)/log(2).

jimmy23013
sumber
1
-inf+nanjSaya tidak berpikir itu bisa ada
Luis Mendo
Ini tidak menampilkan (-inf+nanj)untuk input 2147483647yang memiliki representasi biner dari 31 1s, maka tidak ada nol kedua dalam notasi 32-bit yang ditandatangani (inilah sebabnya mengapa jauh lebih pendek daripada jawaban saya dan jawaban Erik).
Jonathan Allan
Sebenarnya, ketika tidak itu menghasilkan (-inf+nanj)?
Jonathan Allan
... ah saya pikir berhasil, Anda menggunakan opsi yang ditandatangani?
Jonathan Allan
4

Java, ... 194 191 186 Bytes

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 Bytes untuk menggunakan nama variabel yang lebih kecil dan menghapus spasi
-25 Bytes, setelah mengambil variabel lebih pendek dan berkat tips @KevinCruijssen
-18 Bytes, lebih banyak spasi putih, nama fungsi
-3 Bytes, terima kasih kepada @KevinCruijssen, perpendek jika kondisi
-5 Bytes , Terima kasih kepada @Arnold Palmer, @KevinCruijssen, shortening loop

Tidak disatukan

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;
}
0x45
sumber
Selamat datang di PPCG! Ada beberapa hal yang bisa Anda lakukan untuk bermain golf: static bisa dihilangkan; if(n<0||n>o){return 0;}bisa if(n<0|n>o)return 0;( |bukan ||dan tidak ada tanda kurung); bs,, bsadll. semuanya dapat berupa karakter tunggal (tidak pernah menggunakan nama variabel / metode multi-byte dalam kode-golf); Anda dapat menggabungkan ints, seperti ini: int o=2^32-2,c=0,i=x.length,l=i-1;. Dan ada beberapa hal lagi untuk golf. Tips untuk bermain golf di Jawa dan Tips untuk bermain golf dalam semua bahasa mungkin menarik untuk dibaca. Sekali lagi selamat datang, dan nikmati masa tinggal Anda! :)
Kevin Cruijssen
Saya pikir masih ada beberapa ruang yang dapat Anda hapus dalam deklarasi variabel Anda. Selamat datang! :)
musicman523
@ musicman523 Terima kasih, ya perbaiki. 194 untuk sekarang :)
0x45
1
if(c[i]=='0'){j++;}masih bisa di-golf if(c[i]==48)j++;-3 bytes :) EDIT: Atau lebih baik lagi: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}bisa for(;j<2&i>0;j+=c[i--]==48?1:0);untuk -8 bytes.
Kevin Cruijssen
1
@ 0x45 Saya percaya jika Anda mengubah kode @ KevinCruijssen untuk for(;j<2&i>0;j+=c[--i]==48?1:0);itu harus bekerja. Kesalahan berasal dari ipanjangnya string, jadi awalnya Anda mencoba mengindeks melewati batas-batas array. Jika Anda melakukan pra-pengurangan (seperti yang ditunjukkan dalam cuplikan yang diperbarui), maka pertama kali Anda menggunakannya akan mengakses c[c.length-1]seperti dalam kode asli Anda.
Arnold Palmer
3

Kode mesin IA-32, 14 13 byte

Hexdump:

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

Daftar pembongkaran:

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

Menerima input ecx; output dalam al. Mengembalikan 0 pada kesalahan.

Pertama-tama, itu membalikkan input, sehingga dapat menggunakan instruksi pemindaian bit untuk mencari bit yang ditetapkan. Ia mencari bit set paling tidak signifikan, me-reset, mencari bit set paling tidak signifikan lagi, dan mengembalikan hasilnya.

Jika instruksi pemindaian bit tidak menemukan bit yang diset, dokumentasi Intel mengatakan bahwa output tidak terdefinisi. Namun, dalam praktiknya semua prosesor membiarkan register tujuan tidak berubah dalam kasus ini (seperti dicatat oleh Cody Grey, dokumentasi AMD menggambarkan perilaku ini sebagai wajib).

Jadi, ada beberapa kasus berikut:

  1. Tidak ada bit nol (biner 111 ... 1): ecx diatur ke 0 oleh notdan tetap 0
  2. Satu bit nol: ecx diatur ke 0 oleh btrdan tetap 0 setelahbsf
  3. Dua nol bit: ecx diatur ke nilai yang tepat oleh bsf
anatolyg
sumber
Hanya dokumentasi Intel yang mengatakan pemindaian bit pada 0 tidak ditentukan. Dokumentasi AMD secara eksplisit mendokumentasikan bahwa tujuan tidak berubah. Jika Anda ingin menghindari perilaku ini, Anda biasanya akan menambahkan awalan REP untuk mendapatkan LZCNT atau TZCNT, tetapi itu meningkatkan jumlah byte, yang secara alami tidak diinginkan untuk kode golf.
Cody Grey
1
Anda benar-benar melakukan terlalu banyak pekerjaan di sini. Tantangannya tidak mengharuskan Anda untuk membedakan antara kasus di mana tidak ada bit nol dan kasus di mana hanya ada 1 bit nol. Ini memungkinkan Anda untuk mengembalikan 0 (atau nilai negatif apa pun) dalam kedua kasus. Jadi, meskipun 1-byte SALC+ DECadalah sangat pintar, Anda dapat mencukur habis byte dengan hanya menggunakan apa yang ada di ECXpada kedua BSFinstruksi. Satu-satunya hal yang membutuhkan adalah 1-byte XCHGuntuk mendapatkan hasilnya EAXsehingga dapat dikembalikan. Dengan kata lain,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Grey
1
Berikut tautan "coba online" untuk yang di atas . Karena Anda menggunakan ECXsebagai register input, kami perlu memberi tahu GCC untuk menggunakan konvensi panggilan cepat.
Cody Grey
2

Dyalog APL, 20 byte

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

Menggunakan pengindeksan 1, melempar INDEX ERRORjika tidak ada nol detik.

Bagaimana?

⍵⊤⍨- disandikan sebagai

32⍴2 - string biner dengan panjang 32

- balik

~ - negate (0 → 1, 1 → 0)

(⍳32)/⍨ - kompres dengan kisaran 1-32 (meninggalkan indeks nol)

2⊃ - pilih elemen kedua

Uriel
sumber
Anda bisa menghemat banyak byte menggunakan Where ( )
TwiNight
@TwiNight Saya menggunakan dyalog 14
Uriel
TIO memiliki Dyalog 16 jika Anda perlu
TwiNight
1

Jelly , 13 byte

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

Cobalah online!

Menggunakan pengindeksan 1, mendapat bilangan bulat yang tidak ditandatangani sebagai input. Pengembalian 0karena tidak ditemukan.

Erik the Outgolfer
sumber
Ini output 33untuk input 4294967295( 2^32-1, setara 32-bit unsigned of -1)
musicman523
@ musicman523 Hmm, sesuatu berbau amis ...
Erik the Outgolfer
1

Jelly , 12 byte

,4BUFḣ32¬TḊḢ

Tautan monadik, mengambil bilangan bulat, menggunakan opsi yang tidak ditandatangani dan mengembalikan hasil 1-diindeks (mengembalikan 0 bila tidak ada).

Cobalah online!

atau

32Ḷ2*|€n⁸TḊḢ

Coba itu

Bagaimana?

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
Jonathan Allan
sumber
1

kode mesin x86_64, 34 32 byte

Tidak yakin apakah ini pendekatan yang tepat, cukup banyak byte (ternyata tidak ):

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

Cobalah online!

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

Terima kasih @CodyGray untuk -2byte.

ბიმო
sumber
1
Mengitari semua bit mungkin bukan pendekatan yang tepat, baik untuk bermain golf kode atau untuk dunia nyata. Terobosan nyata akan menggunakan salah satu petunjuk yang memungkinkan Anda untuk memanipulasi semua 32 (atau 64) bit sekaligus, seperti BSF, BSR, POPCNT, BT, dll Anatolyg telah mengajukan solusi sepanjang jalur tersebut . Saya belum memutuskan apakah itu bisa dikalahkan. :-p
Cody Grey
1
Omong-omong, trik kode-golf yang berpotensi berguna untuk mengatur register menjadi -1 adalah ATAU dengan -1. Sebagai contoh or ecx, -1,. Itu 3 byte, 1 byte lebih pendek dari XOR + NEG. Ini bukan trik yang bagus ketika tidak bermain golf karena memperkenalkan ketergantungan baca yang salah pada register tujuan, tetapi di sana Anda hanya menggunakan mov ecx, -1dan menghabiskan 5 byte.
Cody Grey
1

8 , 149 byte

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

Kode yang dikomentari

: 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:@
;

Penggunaan dan output

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
Kekacauan Manor
sumber
0

R , 66 byte

w=which.min
x=strtoi(intToBits(scan()));w(x[-w(x)])*any(!x[-w(x)])

membaca dari stdin; kembali 0tanpa nol detik dan tempat sebaliknya.

Cobalah online!

Giuseppe
sumber