Trova il secondo zero


10

Sfida

Dato un numero intero nel formato del complemento a due a 32 bit , restituisce l'indice della seconda cifra zero meno significativa nella rappresentazione binaria, dove un indice 0rappresenta il bit meno significativo e un indice 31rappresenta il bit più significativo.

Se non esiste un secondo zero, è possibile restituire 0, qualsiasi numero negativo, qualsiasi valore di falsa o segnalare un errore in modo sensato nella propria lingua.

Se preferisci, puoi usare l'indicizzazione 1, ma i casi di test seguenti useranno l'indicizzazione 0.

Puoi usare numeri interi senza segno se preferisci; in tal caso, è necessario gestire numeri interi nell'intervallo [0, 2^32). Se si utilizzano numeri interi con segno, è necessario gestire numeri interi nell'intervallo [-2^31, 2^31). I casi di test qui utilizzeranno numeri interi con segno, ma nota che -x(firmato) è 2^32 - x(non firmato).

Casi test

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

punteggio

Questo è , quindi vince la risposta più breve in ogni lingua!


Possiamo invece usare un numero intero senza segno?
— Leaky Nun,

Sì, a condizione che tu gestisca numeri interi nell'intervallo [0, 2^32).
— musicman523,

1
Stiamo prendendo l'intero o la stringa 0b...come input?
— TheLethalCoder

1
@JonathanAllan Immagino di no, dato che sono stato corretto sulla mia risposta di Jelly 2^32-1perché non avrei dovuto tornare 33.
— Erik the Outgolfer,

1
@JonathanAllan La risposta di Erik è corretta. Ho aggiornato le specifiche della sfida per riflettere che dovresti gestire numeri interi a 32 bit se scegli di prenderli come firmati o non firmati
— musicman523

Risposte:


16

Python 2 , 45 byte

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

Provalo online!

Utilizza l'indicizzazione 0, numeri senza segno e genera un errore su nessun secondo zero.

Crea semplicemente un elenco di indici di bit non impostati, dal più basso al più alto, e restituisce la seconda voce.


5
Benvenuti in PPCG! Bel primo post!
— Erik the Outgolfer,

Grazie! In Python sono ancora molto nuovo nei giochi di golf, quindi sono contento che questo codice non sia stato immediatamente eliminato.
— Arnold Palmer,

Ottimo :) che dire di n = 2147483647?
— mdahmoune,

@mdahmoune 2 ** 31-1 dovrebbe fuoriuscire poiché la sua rappresentazione binaria a 32 bit è 0b0111111111111111111111111111111111, che non ha un secondo 0. A meno che non mi manchi qualcosa ...
— Arnold Palmer,

6

JavaScript (ES6), 34 byte

Restituisce un indice basato su 0 o -1se non viene trovato alcun secondo zero.

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

Casi test

Espressione alternativa

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

Versione ricorsiva, 42 byte

Restituisce un indice basato su 0 o falsese non viene trovato alcun secondo zero.

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

Come?

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

Casi test

Versione alternativa suggerita da Neil, 41 byte

Restituisce un indice basato su 0 o genera un errore di ricorsione eccessivo se non viene trovato alcun secondo zero.

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

Versione ricorsiva a 41 byte:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
— Neil,

5

Gelatina , 7 byte

|‘‘&~l2

Provalo online!

Emette qualcosa che non rientra nell'intervallo [1,31] se non c'è il secondo zero. Questo include 32 33e (-inf+nanj). Immagino che abbia un senso.

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


1
-inf+nanjNon pensavo che potesse esistere
— Luis Mendo il

Non viene emesso (-inf+nanj)per un input 2147483647con una rappresentazione binaria di 31 1s, quindi nessun secondo zero nella notazione firmata a 32 bit (ecco perché è molto più breve delle mie e delle risposte di Erik).
— Jonathan Allan,

In realtà, quando non si produce (-inf+nanj)?
— Jonathan Allan,

... ah penso che abbia funzionato, stai usando l'opzione firmata?
— Jonathan Allan,

4

Java, ... 194 191 186 byte

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 byte per l'utilizzo di nomi di variabili più piccoli e la rimozione di spazi bianchi
-25 byte, dopo aver acquisito variabili ancora più brevi e grazie ai suggerimenti di @KevinCruijssen
-18 byte, più spazi bianchi, nome della funzione
-3 byte, grazie a @KevinCruijssen, accorciando se condizione
-5 byte , Grazie a @Arnold Palmer, @KevinCruijssen, loop accorciato

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

Benvenuti in PPCG! Ci sono alcune cose che puoi giocare a golf: static possono essere rimosse; if(n<0||n>o){return 0;}può essere if(n<0|n>o)return 0;( |anziché ||e senza parentesi); bs, bsaecc. possono essere tutti caratteri singoli (non usare mai nomi di variabili / metodi multibyte in code-golf); È possibile combinare ints, in questo modo: int o=2^32-2,c=0,i=x.length,l=i-1;. E ci sono altre cose da golf. Suggerimenti per giocare a golf in Java e Suggerimenti per giocare a golf in tutte le lingue potrebbero essere interessanti da leggere. Ancora benvenuto, e goditi il ​​tuo soggiorno! :)
— Kevin Cruijssen il

Penso che ci siano ancora un paio di spazi che è possibile rimuovere nelle dichiarazioni delle variabili. Benvenuto! :)
— musicman523

@ musicman523 Grazie, sì, l'ho risolto. 194 per ora :)
— 0x45,

1
if(c[i]=='0'){j++;}può ancora essere golfato if(c[i]==48)j++;per -3 byte :) MODIFICA: O meglio ancora: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}può essere for(;j<2&i>0;j+=c[i--]==48?1:0);per -8 byte.
— Kevin Cruijssen,

1
@ 0x45 Credo che se cambi il codice di KevinCruijssen in for(;j<2&i>0;j+=c[--i]==48?1:0);esso dovrebbe funzionare. L'errore deriva idall'essere la lunghezza della stringa, quindi inizialmente stai provando a indicizzare oltre i limiti dell'array. Se esegui un pre-decremento (come mostrato nello snippet aggiornato), la prima volta che lo usi accederà c[c.length-1]come nel codice originale.
— Arnold Palmer,


3

Codice macchina IA-32, 14 13 byte

hexdump:

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

Elenco di smontaggio:

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

Riceve input in ecx; l'uscita è in al. Restituisce 0 in caso di errore.

Prima di tutto, inverte l'input, quindi può usare le istruzioni di scansione dei bit per cercare i bit impostati. Cerca il bit set meno significativo, lo reimposta, cerca nuovamente il bit set meno significativo e restituisce il risultato.

Se l'istruzione di scansione bit non trova alcun bit impostato, la documentazione Intel indica che l'output non è definito. Tuttavia, in pratica tutti i processori lasciano invariato il registro di destinazione in questo caso (come notato da Cody Gray, la documentazione AMD descrive questo comportamento come obbligatorio).

Quindi, ci sono i seguenti casi:

  1. Nessun bit zero (binario 111 ... 1): ecx è impostato su 0 da note rimane 0
  2. Un bit zero: ecx è impostato su 0 da btre rimane 0 dopobsf
  3. Due bit zero: ecx è impostato sul valore corretto da bsf

È solo la documentazione di Intel che afferma che le scansioni di bit su 0 non sono definite. La documentazione di AMD documenta esplicitamente che la destinazione è invariata. Se si desidera evitare questo comportamento, si dovrebbe normalmente aggiungere il prefisso REP per ottenere LZCNT o TZCNT, ma ciò aumenta il conteggio dei byte, che è naturalmente indesiderabile per il golf del codice.
— Cody Gray,

1
In realtà stai facendo troppo lavoro qui. La sfida non richiede di discriminare tra il caso in cui non ci sono bit zero e il caso in cui esiste solo 1 bit zero. Ti consente di restituire 0 (o qualsiasi valore negativo) in entrambi i casi. Quindi, sebbene 1 byte SALC+ DECsia estremamente intelligente, puoi radere via un byte semplicemente usando qualunque cosa sia presente nella ECXseconda BSFistruzione. L'unica cosa che richiede è un 1 byte XCHGper ottenere il risultato in EAXmodo che possa essere restituito. In altre parole,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
— Cody Gray il

1
Ecco un link "provalo online" per quanto sopra . Dato che stai usando ECXcome registro di input, dobbiamo dire a GCC di usare la convenzione di chiamata di chiamata rapida.
— Cody Gray,

2

Dyalog APL, 20 byte

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

Utilizza 1-indicizzazione, genera INDEX ERRORin caso di nessun secondo zero.

Come?

⍵⊤⍨- codifica ⍵come a

32⍴2 - stringa binaria di lunghezza 32

⌽ - inversione

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

(⍳32)/⍨ - comprimi con l'intervallo 1-32 (lasciando indici di zeri)

2⊃ - scegli il secondo elemento


È possibile salvare molti byte utilizzando Where ( ⍸)
— TwiNight

@TwiNight Uso dyalog 14
— Uriel il

TIO ha Dyalog 16 se ne hai bisogno
— TwiNight


1

Gelatina , 12 byte

,4BUFḣ32¬TḊḢ

Un collegamento monadico, che accetta un numero intero, utilizza l'opzione unsigned e restituisce il risultato con 1 indice (restituisce 0 quando non esiste nessuno).

Provalo online!

o

32Ḷ2*|€n⁸TḊḢ

Prova questo

Come?

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

codice macchina x86_64, 34 32 byte

Non sono sicuro che questo sia l'approccio giusto, molti byte (si scopre che non lo è ):

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

Provalo 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

Grazie @CodyGray per i -2byte.


1
Il looping di tutti i bit non è probabilmente l'approccio giusto, né per il golf del codice o per il mondo reale. La vera svolta sarà utilizzando una delle istruzioni che consentono di manipolare tutti i 32 (o 64) bit in una sola volta, come BSF, BSR, POPCNT, BT, ecc Anatolyg ha presentato una soluzione in questo senso . Non ho ancora deciso se può essere battuto. :-p
— Cody Gray,

1
A proposito, un trucco potenzialmente utile per giocare a code-golf per impostare un registro su -1 è OR o con -1. Ad esempio or ecx, -1,. Sono 3 byte, 1 byte più corto di XOR + NEG. Questo non è un buon trucco quando non si gioca a golf perché introduce una dipendenza di lettura falsa dal registro di destinazione, ma lì si utilizzerebbero mov ecx, -1e si spenderebbero i 5 byte.
— Cody Gray,

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

Codice commentato

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

Utilizzo e 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

0

R , 66 byte

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

legge dallo stdin; ritorna 0per nessun secondo zero e il posto altrimenti.

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.