Finde die zweite Null


10

Herausforderung

Gegeben eine ganze Zahl in einem 32-Bit - Zweier-Komplement - Format, kehren den Index der zweiten niedrigstwertigen Ziffer Null in der binären Darstellung, wobei ein Index für 0das niedrigstwertige Bit darstellt, und ein Index 31repräsentiert das höchstwertige Bit.

Wenn es keine zweite Null gibt, können Sie 0, eine negative Zahl oder einen falschen Wert zurückgeben oder einen Fehler auf eine Weise melden, die in Ihrer Sprache sinnvoll ist.

Sie können die 1-Indizierung verwenden, wenn Sie dies bevorzugen. In den folgenden Testfällen wird jedoch die 0-Indizierung verwendet.

Sie können vorzeichenlose Ganzzahlen verwenden, wenn Sie dies bevorzugen. Wenn Sie dies tun, müssen Sie Ganzzahlen im Bereich verarbeiten [0, 2^32). Wenn Sie vorzeichenbehaftete Ganzzahlen verwenden, müssen Sie Ganzzahlen im Bereich verarbeiten [-2^31, 2^31). In den Testfällen werden vorzeichenbehaftete Ganzzahlen verwendet. Beachten Sie jedoch, dass -x(signiert) 2^32 - x(nicht signiert) ist .

Testfälle

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

Wertung

Dies ist , also gewinnt die kürzeste Antwort in jeder Sprache!


Können wir stattdessen eine vorzeichenlose Ganzzahl verwenden?
Undichte Nonne

Ja, das können Sie, solange Sie dann Ganzzahlen im Bereich verarbeiten [0, 2^32).
musicman523

1
Nehmen wir die Ganzzahl oder den String 0b...als Eingabe?
TheLethalCoder

1
@ JonathanAllan Ich denke nicht, da ich in meiner Jelly-Antwort mit korrigiert wurde, 2^32-1weil ich nicht zurückkehren sollte 33.
Erik der Outgolfer

1
@ JonathanAllan Eriks Antwort ist richtig. Ich habe die Herausforderungsspezifikation aktualisiert, um zu berücksichtigen, dass Sie 32-Bit-Ganzzahlen verarbeiten sollten, unabhängig davon, ob Sie sie als signiert oder nicht signiert verwenden
möchten

Antworten:


16

Python 2 , 45 Bytes

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

Probieren Sie es online aus!

Verwendet 0-Indizierung, vorzeichenlose Zahlen und wirft einen Fehler auf keine zweite Null.

Erstellt einfach eine Liste von Indizes nicht gesetzter Bits vom niedrigsten zum höchsten und gibt den zweiten Eintrag zurück.


5
Willkommen bei PPCG! Schöner erster Beitrag!
Erik der Outgolfer

Vielen Dank! Ich bin noch sehr neu in der Golf-Trickerei in Python, daher bin ich froh, dass dieser Code nicht sofort übernommen wurde.
Arnold Palmer

Großartig :) was ist mit n = 2147483647?
Mdahmoune

@mdahmoune 2 ** 31-1 sollte ausfallen, da seine binäre Darstellung in 32 Bit 0b01111111111111111111111111111111 ist, die keine zweite 0 hat. Es sei denn, ich vermisse etwas ...
Arnold Palmer

6

JavaScript (ES6), 34 Byte

Gibt einen 0-basierten Index zurück oder -1wenn keine zweite Null gefunden wird.

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

Testfälle

Alternativer Ausdruck

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

Rekursive Version, 42 Bytes

Gibt einen 0-basierten Index zurück oder falsewenn keine zweite Null gefunden wird.

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

Wie?

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

Testfälle

Alternative Version von Neil vorgeschlagen, 41 Bytes

Gibt einen 0-basierten Index zurück oder löst einen zu großen Rekursionsfehler aus , wenn keine zweite Null gefunden wird.

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

41-Byte-rekursive Version:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil

5

Gelee , 7 Bytes

|‘‘&~l2

Probieren Sie es online aus!

Es gibt etwas aus, das nicht im Bereich [1,31] liegt, wenn es nicht die zweite Null gibt. Dies beinhaltet 32 33und (-inf+nanj). Ich denke, das macht Sinn.

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


1
-inf+nanjIch hätte nicht gedacht, dass es das überhaupt geben könnte
Luis Mendo

Es wird nicht (-inf+nanj)für einen Eingang ausgegeben, 2147483647der eine binäre Darstellung von 31 1s hat, daher keine zweite Null in 32-Bit-Notation mit Vorzeichen (aus diesem Grund ist er so viel kürzer als meine und Eriks Antworten).
Jonathan Allan

Eigentlich , wenn nicht sie produzieren (-inf+nanj)?
Jonathan Allan

... ah, ich denke, es hat geklappt, Sie verwenden die signierte Option?
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 für die Verwendung kleinerer Variablennamen und das Entfernen von Leerzeichen
-25 Bytes, nachdem noch kürzere Variablen verwendet wurden und dank @ KevinCruijssen-Tipps
-18 Bytes, mehr Leerzeichen, Funktionsname
-3 Bytes, dank @KevinCruijssen, Verkürzung bei Bedingung
-5 Bytes , Dank an @Arnold Palmer, @KevinCruijssen, Verkürzungsschleife

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

Willkommen bei PPCG! Es gibt einige Dinge, die Sie Golf spielen können: static können entfernt werden; if(n<0||n>o){return 0;}kann sein if(n<0|n>o)return 0;( |anstelle von ||und keine Klammern); bs, bsausw. können alle einzelne Zeichen sein (verwenden Sie im Code-Golf niemals Mehrbyte-Variablen- / Methodennamen); Sie können ints wie folgt kombinieren : int o=2^32-2,c=0,i=x.length,l=i-1;. Und es gibt noch einige Dinge zum Golfen. Tipps zum Golfen in Java und Tipps zum Golfen in allen Sprachen könnten interessant sein. Wieder willkommen und genießen Sie Ihren Aufenthalt! :)
Kevin Cruijssen

Ich denke, es gibt noch ein paar Leerzeichen, die Sie in Ihren Variablendeklarationen entfernen können. Herzlich willkommen! :)
musicman523

@ musicman523 Danke, ja, das Problem wurde behoben. 194 für jetzt :)
0x45

1
if(c[i]=='0'){j++;}kann immer noch if(c[i]==48)j++;für -3 Bytes gespielt werden :) EDIT: Oder noch besser: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}kann for(;j<2&i>0;j+=c[i--]==48?1:0);für -8 Bytes sein.
Kevin Cruijssen

1
@ 0x45 Ich glaube, wenn Sie den Code von @ KevinCruijssen ändern, for(;j<2&i>0;j+=c[--i]==48?1:0);sollte er funktionieren. Der Fehler ergibt sich aus ider Länge der Zeichenfolge. Sie versuchen also zunächst, über die Grenzen des Arrays hinaus zu indizieren. Wenn Sie eine Vordekrementierung durchführen (wie im aktualisierten Snippet gezeigt), wird bei der ersten Verwendung c[c.length-1]wie in Ihrem Originalcode darauf zugegriffen.
Arnold Palmer


3

IA-32 Maschinencode, 14 13 Bytes

Hexdump:

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

Auflistung der Demontage:

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

Empfängt Eingaben in ecx; Ausgabe ist in al. Gibt bei einem Fehler 0 zurück.

Zunächst wird die Eingabe invertiert, sodass mithilfe der Bit-Scan-Anweisungen nach gesetzten Bits gesucht werden kann. Es sucht nach dem niedrigstwertigen gesetzten Bit, setzt es zurück, sucht erneut nach dem niedrigstwertigen gesetzten Bit und gibt das Ergebnis zurück.

Wenn der Bit-Scan-Befehl kein gesetztes Bit findet, heißt es in der Intel-Dokumentation, dass die Ausgabe undefiniert ist. In der Praxis lassen jedoch alle Prozessoren das Zielregister in diesem Fall unverändert (wie von Cody Gray angegeben, beschreibt die AMD-Dokumentation dieses Verhalten als obligatorisch).

Es gibt also folgende Fälle:

  1. Keine Nullbits (binär 111 ... 1): ecx wird von auf 0 gesetzt notund bleibt 0
  2. Ein Nullbit: ecx wird von auf 0 gesetzt btrund bleibt danach 0bsf
  3. Zwei Nullbits: ecx wird durch auf den richtigen Wert gesetzt bsf

Nur in der Dokumentation von Intel heißt es, dass Bit-Scans auf 0 undefiniert sind. Die Dokumentation von AMD dokumentiert ausdrücklich, dass das Ziel unverändert ist. Wenn Sie dieses Verhalten vermeiden möchten, fügen Sie normalerweise das REP-Präfix hinzu, um entweder LZCNT oder TZCNT zu erhalten. Dies erhöht jedoch die Anzahl der Bytes, was für Code-Golf natürlich unerwünscht ist.
Cody Gray

1
Du machst hier tatsächlich zu viel Arbeit. Die Herausforderung erfordert nicht, dass Sie zwischen dem Fall, in dem es keine Nullbits gibt, und dem Fall, in dem es nur 1 Nullbit gibt, unterscheiden. In beiden Fällen können Sie 0 (oder einen beliebigen negativen Wert) zurückgeben. Also, auch wenn das 1-Byte SALC+ DECist extrem klug, können Sie ein Byte nur mit , was abrasieren ist in ECXab dem zweiten BSFBefehl. Das einzige, was benötigt wird, ist ein 1-Byte XCHG, um das Ergebnis zu erhalten, EAXdamit es zurückgegeben werden kann. Mit anderen Worten,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Gray

1
Hier ist ein Link "online ausprobieren" für das oben Gesagte . Da Sie ECXals Eingaberegister verwenden, müssen wir GCC anweisen, die Fastcall-Aufrufkonvention zu verwenden.
Cody Gray

2

Dyalog APL, 20 Bytes

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

Verwendet 1-Indexierung, wirft, INDEX ERRORwenn keine zweite Null vorliegt.

Wie?

⍵⊤⍨- als kodieren

32⍴2 - Binärzeichenfolge der Länge 32

- umkehren

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

(⍳32)/⍨ - mit dem Bereich 1-32 komprimieren (Indizes von Nullen belassen)

2⊃ - Wählen Sie das zweite Element


Sie könnten eine Menge Bytes mit Where ( )
TwiNight

@ TwiNight Ich benutze Dyalog 14
Uriel

TIO hat Dyalog 16, wenn Sie brauchen
TwiNight


1

Gelee , 12 Bytes

,4BUFḣ32¬TḊḢ

Eine monadische Verknüpfung, die eine Ganzzahl verwendet, die Option ohne Vorzeichen verwendet und das 1-indizierte Ergebnis zurückgibt (gibt 0 zurück, wenn keine vorhanden ist).

Probieren Sie es online aus!

oder

32Ḷ2*|€n⁸TḊḢ

Versuch das

Wie?

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 Maschinencode, 34 32 Bytes

Ich bin mir nicht sicher, ob dies der richtige Ansatz ist, ziemlich viele Bytes (es stellt sich heraus, dass dies nicht der Fall ist ):

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

Probieren Sie es online aus!

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

Danke @CodyGray für die -2Bytes.


1
Das Durchlaufen aller Teile ist wahrscheinlich nicht der richtige Ansatz, weder für Code-Golf noch für die reale Welt. Der wirkliche Durchbruch wird mit einer der Anweisungen sein, mit denen Sie alle 32 (oder 64) Bits auf einmal zu manipulieren, wie BSF, BSR, POPCNT, BTetc. Anatolyg hat eine Lösung in dieser Richtung vorgelegt . Ich habe noch nicht festgestellt, ob es zu schlagen ist. :-p
Cody Gray

1
Übrigens besteht ein potenziell nützlicher Code-Golf-Trick, um ein Register auf -1 zu setzen, darin, es mit -1 ODER zu verknüpfen. Zum Beispiel or ecx, -1. Das sind 3 Bytes, 1 Byte kürzer als XOR + NEG. Dies ist kein guter Trick, wenn Sie nicht Golf spielen, da dadurch eine falsche Leseabhängigkeit vom Zielregister eingeführt wird. Dort würden Sie jedoch nur mov ecx, -1die 5 Bytes verwenden und ausgeben.
Cody Gray

1

8. 149 Bytes

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

Kommentierter Code

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

Verwendung und Ausgabe

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.