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.