Znajdź drugą zero

10

Wyzwanie

Biorąc pod uwagę liczbę całkowitą w 32-bitowym formacie uzupełnienia do dwóch , zwraca indeks drugiej najmniej znaczącej cyfry zero w reprezentacji binarnej, gdzie indeks 0reprezentuje najmniej znaczący bit, a indeks 31reprezentuje najbardziej znaczący bit.

Jeśli nie ma drugiego zera, możesz zwrócić 0, dowolną liczbę ujemną, dowolną wartość fałszowania lub zgłosić błąd w sposób, który ma sens w twoim języku.

Jeśli wolisz, możesz użyć indeksowania 1, ale poniższe przypadki testowe będą używać indeksowania 0.

Możesz użyć liczb całkowitych bez znaku, jeśli wolisz; jeśli to zrobisz, musisz obsługiwać liczby całkowite w zakresie [0, 2^32). Jeśli używasz liczb całkowitych ze znakiem, musisz obsługiwać liczby całkowite z zakresu [-2^31, 2^31). Przypadki testowe wykorzystają tutaj liczby całkowite ze znakiem, ale należy pamiętać, że -x(podpisany) jest 2^32 - x(niepodpisany).

Przypadki testowe

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

Punktacja

To jest , więc wygrywa najkrótsza odpowiedź w każdym języku!

musicman523
źródło
Czy zamiast tego możemy użyć liczby całkowitej bez znaku?
Leaky Nun
Tak, możesz tak długo, jak długo będziesz traktować liczby całkowite w zakresie [0, 2^32).
musicman523
1
Czy bierzemy na 0b...wejściu liczbę całkowitą lub ciąg ?
TheLethalCoder
1
@JonathanAllan Chyba nie, ponieważ poprawiono moją odpowiedź na żelki, ponieważ 2^32-1nie powinienem wracać 33.
Erik the Outgolfer,
1
@JonathanAllan Erik odpowiedź jest poprawna. Zaktualizowałem specyfikację wyzwania, aby odzwierciedlić, że powinieneś obsługiwać 32-bitowe liczby całkowite, niezależnie od tego, czy wybierzesz je jako podpisane czy niepodpisane
musicman523,

Odpowiedzi:

16

Python 2 , 45 bajtów

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

Wypróbuj online!

Używa indeksowania 0, liczb bez znaku i zgłasza błąd nie zerując drugiego zera.

Po prostu tworzy listę indeksów nie ustawionych bitów, od najniższego do najwyższego, i zwraca drugi wpis.

Arnold Palmer
źródło
5
Witamy w PPCG! Miły pierwszy post!
Erik the Outgolfer
Dzięki! Nadal jestem naprawdę nowy w golfie w trickach golfowych w Pythonie, więc cieszę się, że ten kod nie został od razu odegrany w golfa.
Arnold Palmer,
Świetnie :) a n = 2147483647?
mdahmoune
@mdahmoune 2 ** 31-1 powinien wyskoczyć błąd, ponieważ jego binarna reprezentacja w 32 bitach to 0b01111111111111111111111111111111, która nie ma sekundy 0. Chyba że coś mi brakuje ...
Arnold Palmer
6

JavaScript (ES6), 34 bajty

Zwraca indeks oparty na 0 lub -1jeśli nie znaleziono drugiego zera.

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

Przypadki testowe

Alternatywne wyrażenie

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

Wersja rekurencyjna, 42 bajty

Zwraca indeks oparty na 0 lub falsejeśli nie znaleziono drugiego zera.

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

W jaki sposób?

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

Przypadki testowe

Alternatywna wersja sugerowana przez Neila, 41 bajtów

Zwraca indeks oparty na 0 lub generuje zbyt duży błąd rekurencji, jeśli nie zostanie znalezione drugie zero.

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Arnauld
źródło
41-bajtowa wersja rekurencyjna:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil
5

Galaretka , 7 bajtów

|‘‘&~l2

Wypróbuj online!

Wyprowadza coś poza zakresem [1,31], jeśli nie ma drugiego zera. Obejmuje to 32 33i (-inf+nanj). To chyba ma sens.

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

jimmy23013
źródło
1
-inf+nanjNie sądziłem, że może to nawet istnieć
Luis Mendo
Nie generuje danych (-inf+nanj)wejściowych, 2147483647których binarna reprezentacja wynosi 31 1s, a zatem nie ma drugiego zera w 32-bitowej notacji ze znakiem (dlatego jest o wiele krótsza niż moja i odpowiedzi Erika).
Jonathan Allan
Faktycznie, gdy ma ona produkować (-inf+nanj)?
Jonathan Allan
... ah myślę, że się udało, używasz podpisanej opcji?
Jonathan Allan
4

Java, ... 194 191 186 bajtów

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 Bajtów za używanie mniejszych nazw zmiennych i usuwanie białych spacji
-25 Bajtów, po wzięciu jeszcze krótszych zmiennych i dzięki poradom @KevinCruijssen
-18 Bajtów, więcej białych spacji, nazwa funkcji
-3 Bajtów, dzięki @KevinCruijssen, skracanie warunku
-5 Bajtów , Dzięki @Arnold Palmer, @KevinCruijssen, skrócenie pętli

Nie golfił

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
źródło
Witamy w PPCG! Istnieje kilka rzeczy, na które możesz grać w golfa: static można je usunąć; if(n<0||n>o){return 0;}może być if(n<0|n>o)return 0;( |zamiast ||i bez nawiasów); bs, bsaitp. mogą być pojedynczymi znakami (nigdy nie używaj wielobajtowych nazw zmiennych / metod w golfie kodowym); Można łączyć ints, tak: int o=2^32-2,c=0,i=x.length,l=i-1;. Jest jeszcze kilka rzeczy do gry w golfa. Wskazówki dotyczące gry w golfa w Javie oraz wskazówki dotyczące gry we wszystkie języki mogą być interesujące do przeczytania. Jeszcze raz witamy i życzymy miłego pobytu! :)
Kevin Cruijssen
Myślę, że wciąż jest kilka spacji, które można usunąć z deklaracji zmiennych. Witamy! :)
musicman523,
@ musicman523 Dzięki, tak, naprawiłem to. 194 na razie :)
0x45
1
if(c[i]=='0'){j++;}nadal można grać w golfa do if(c[i]==48)j++;-3 bajtów :) EDYCJA: Lub jeszcze lepiej: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}może być for(;j<2&i>0;j+=c[i--]==48?1:0);do -8 bajtów.
Kevin Cruijssen
1
@ 0x45 Uważam, że jeśli zmienisz kod @ KevinCruijssen, for(;j<2&i>0;j+=c[--i]==48?1:0);powinien on działać. Błąd pochodzi z itego, że jest długością łańcucha, więc początkowo próbujesz indeksować poza granice tablicy. Jeśli zrobisz wstępną dekrementację (jak pokazano w zaktualizowanym fragmencie), to przy pierwszym użyciu użyje go, c[c.length-1]podobnie jak w oryginalnym kodzie.
Arnold Palmer
3

Kod maszynowy IA-32, 14 13 bajtów

Hexdump:

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

Lista demontażu:

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

Odbiera dane wejściowe ecx; wyjście jest w al. Zwraca 0 w przypadku błędu.

Przede wszystkim odwraca dane wejściowe, dzięki czemu może użyć instrukcji skanowania bitów, aby wyszukać ustawione bity. Poszukuje najmniej znaczącego zestawu bitów, resetuje go, ponownie szuka najmniej znaczącego zestawu bitów i zwraca wynik.

Jeśli instrukcja skanowania bitów nie znajdzie żadnego ustawionego bitu, dokumentacja Intela mówi, że wyjście jest niezdefiniowane. Jednak w praktyce wszystkie procesory pozostawiają w tym przypadku rejestr docelowy bez zmian (jak zauważył Cody Gray, dokumentacja AMD opisuje to zachowanie jako obowiązkowe).

Istnieją więc następujące przypadki:

  1. Bez bitów zerowych (binarnie 111 ... 1): ecx jest ustawiony na 0 przez noti pozostaje 0
  2. Jeden bit zero: ecx jest ustawiany na 0 przez btri pozostaje 0 pobsf
  3. Dwa bity zerowe: ecx jest ustawiany na właściwą wartość przez bsf
anatolig
źródło
Tylko dokumentacja Intela mówi, że skany bitów na 0 są niezdefiniowane. Dokumentacja AMD wyraźnie dokumentuje, że miejsce docelowe pozostaje niezmienione. Jeśli chcesz uniknąć tego zachowania, zwykle dodajesz przedrostek REP, aby uzyskać LZCNT lub TZCNT, ale to zwiększa liczbę bajtów, co oczywiście nie jest pożądane dla kodu golfa.
Cody Gray
1
Robisz tu zbyt dużo pracy. Wyzwanie nie wymaga rozróżnienia między przypadkiem, w którym nie ma zerowych bitów, a przypadkiem, w którym jest tylko 1 bit zerowy. Pozwala zwrócić 0 (lub dowolną wartość ujemną) w obu przypadkach. Tak więc, chociaż 1-bajtowy SALC+ DECjest wyjątkowo sprytny, możesz ogolić bajt, używając tylko tego, co jest w ECXdrugiej BSFinstrukcji. Jedyne, co wymaga, to 1 bajt, XCHGaby uzyskać wynik, EAXaby mógł zostać zwrócony. Innymi słowy,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Gray
1
Oto link „wypróbuj online” dla powyższego . Ponieważ używasz ECXjako rejestru wejściowego, musimy powiedzieć GCC, aby użyła konwencji wywoływania szybkiego połączenia.
Cody Gray
2

Dyalog APL, 20 bajtów

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

Wykorzystuje indeksowanie 1, rzuca INDEX ERRORw przypadku braku drugiego zera.

W jaki sposób?

⍵⊤⍨- kodować jako

32⍴2 - ciąg binarny o długości 32

- odwrócić

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

(⍳32)/⍨ - kompresuj z zakresu 1-32 (pozostawiając indeksy zer)

2⊃ - wybierz drugi element

Uriel
źródło
Możesz zaoszczędzić wiele bajtów za pomocą Where ( )
TwiNight
@TwiNight Używam dyalog 14
Uriel
TIO ma Dyalog 16, jeśli potrzebujesz
TwiNight
1

Galaretka , 13 bajtów

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

Wypróbuj online!

Używa indeksowania 1, jako wartość wejściową przyjmuje liczbę całkowitą bez znaku. Zwraca 0za nie znaleziono.

Erik the Outgolfer
źródło
Dane wyjściowe 33dla wejścia 4294967295( 2^32-132-bitowy ekwiwalent bez znaku -1)
musicman523
@ musicman523 Hmm, coś pachnie podejrzanie ...
Erik the Outgolfer
1

Galaretka , 12 bajtów

,4BUFḣ32¬TḊḢ

Łącze monadyczne, przyjmujące liczbę całkowitą, wykorzystujące opcję niepodpisaną i zwracające wynik 1-indeksowany (zwraca 0, jeśli nie istnieje).

Wypróbuj online!

lub

32Ḷ2*|€n⁸TḊḢ

Spróbuj tego

W jaki sposób?

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
źródło
1

kod maszynowy x86_64, 34 32 bajty

Nie jestem pewien, czy jest to właściwe podejście, całkiem sporo bajtów (okazuje się, że tak nie jest ):

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

Wypróbuj 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

Dzięki @CodyGray za -2bajty.

ბიმო
źródło
1
Pętla przez wszystkie bity prawdopodobnie nie jest właściwym podejściem, ani do gry w golfa kodu, ani do prawdziwego świata. Prawdziwym przełomem będzie przy użyciu jednego z instrukcjami, które pozwalają manipulować wszystkie 32 (lub 64) bitów na raz, jak BSF, BSR, POPCNT, BT, itd Anatolyg został złożony rozwiązanie wzdłuż tych linii . Nie ustaliłem jeszcze, czy da się go pokonać. :-p
Cody Gray
1
Nawiasem mówiąc, potencjalnie użyteczną sztuczką do gry w golfa przy ustawianiu rejestru na -1 jest OR lub -1. Na przykład or ecx, -1. To 3 bajty, 1 bajt krótszy niż XOR + NEG. Nie jest to dobra sztuczka, gdy nie gra się w golfa, ponieważ wprowadza zależność od fałszywego odczytu od rejestru docelowego, ale tam wystarczy użyć mov ecx, -1i wydać 5 bajtów.
Cody Gray
1

8th , 149 bajtów

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

Skomentowany kod

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

Wykorzystanie i wydajność

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
Dwór Chaosu
źródło
0

R , 66 bajtów

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

czyta ze standardowego; zwroty0 zero sekund, a miejsce inaczej.

Wypróbuj online!

Giuseppe
źródło