Trouvez le deuxième zéro


10

Défi

Étant donné un entier au format complément à deux de 32 bits , retournez l'index du deuxième chiffre zéro le moins significatif dans la représentation binaire, où un index de 0représente le bit le moins significatif et un index de 31représente le bit le plus significatif.

S'il n'y a pas de second zéro, vous pouvez renvoyer 0, tout nombre négatif, toute valeur falsifiée ou signaler une erreur d'une manière qui a du sens dans votre langue.

Vous pouvez utiliser l'indexation 1 si vous préférez, mais les cas de test ci-dessous utiliseront l'indexation 0.

Vous pouvez utiliser des entiers non signés si vous préférez; si vous le faites, vous devez alors gérer des entiers dans la plage [0, 2^32). Si vous utilisez des entiers signés, vous devez gérer les entiers de la plage [-2^31, 2^31). Les cas de test ici utiliseront des entiers signés, mais notez que -x(signé) est2^32 - x (non signé).

Cas de test

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

Notation

C'est le , donc la réponse la plus courte dans chaque langue gagne!


Pouvons-nous utiliser un entier non signé à la place?
Leaky Nun

Oui, tant que vous gérez ensuite des entiers dans la plage [0, 2^32).
musicman523

1
Prenons-nous l'entier ou la chaîne 0b...en entrée?
TheLethalCoder

1
@JonathanAllan Je suppose que non, car j'ai été corrigé sur ma réponse Jelly 2^32-1parce que je n'étais pas censé revenir 33.
Erik the Outgolfer

1
@JonathanAllan Erik est correcte. J'ai mis à jour la spécification de défi pour refléter que vous devez gérer les entiers 32 bits que vous choisissiez de les prendre comme signés ou non signés
musicman523

Réponses:


16

Python 2 , 45 octets

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

Essayez-le en ligne!

Utilise l'indexation 0, les nombres non signés et renvoie une erreur sur aucun deuxième zéro.

Crée simplement une liste d'index de bits non définis, du plus bas au plus élevé, et renvoie la deuxième entrée.


5
Bienvenue chez PPCG! Bon premier post!
Erik the Outgolfer

Merci! Je suis encore très nouveau dans la supercherie au golf en Python, donc je suis content que ce code n'ait pas été joué immédiatement.
Arnold Palmer

Super :) qu'en est-il de n = 2147483647?
mdahmoune

@mdahmoune 2 ** 31-1 devrait afficher une erreur car sa représentation binaire en 32 bits est 0b011111111111111111111111111111111, qui n'a pas de second 0. Sauf si je manque quelque chose ...
Arnold Palmer

6

JavaScript (ES6), 34 octets

Renvoie un index basé sur 0, ou -1si aucun deuxième zéro n'est trouvé.

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

Cas de test

Expression alternative

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

Version récursive, 42 octets

Renvoie un index basé sur 0, ou falsesi aucun deuxième zéro n'est trouvé.

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

Comment?

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

Cas de test

Version alternative suggérée par Neil, 41 octets

Renvoie un index basé sur 0 ou renvoie une erreur de récursivité trop importante si aucun deuxième zéro n'est trouvé.

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

Version récursive de 41 octets:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil

5

Gelée , 7 octets

|‘‘&~l2

Essayez-le en ligne!

Il produit quelque chose qui n'est pas dans la plage [1,31] s'il n'y a pas le deuxième zéro. Cela comprend 32 33et (-inf+nanj). Je suppose que cela a du sens.

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


1
-inf+nanjJe ne pensais même pas que cela pourrait exister
Luis Mendo

Il ne sort pas (-inf+nanj)pour une entrée 2147483647dont la représentation binaire est de 31 1s, donc pas de second zéro en notation signée 32 bits (c'est pourquoi il est tellement plus court que le mien et les réponses d'Erik).
Jonathan Allan

En fait, quand produit- il (-inf+nanj)?
Jonathan Allan

... ah je pense que ça a marché, vous utilisez l'option signée?
Jonathan Allan

4

Java, ... 194191186 octets

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 octets pour utiliser des noms de variables plus petits et supprimer les espaces blancs
-25 octets, après avoir pris des variables encore plus courtes et grâce aux astuces @KevinCruijssen
-18 octets, plus d'espaces blancs, le nom de la fonction
-3 octets, grâce à @KevinCruijssen, raccourcir si condition
-5 octets , Merci à @Arnold Palmer, @KevinCruijssen, boucle de raccourcissement

Non golfé

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

Bienvenue chez PPCG! Il y a pas mal de choses que vous static pouvez jouer au golf: peuvent être supprimées; if(n<0||n>o){return 0;}peut être if(n<0|n>o)return 0;( |au lieu de ||et pas de crochets); bs, bsaEtc. peuvent tous être des caractères simples (ne jamais utiliser de noms de variables multi-octets / méthode dans le code-golf); Vous pouvez combiner ints, comme ceci: int o=2^32-2,c=0,i=x.length,l=i-1;. Et il y a encore plus de choses au golf. Des conseils pour jouer au golf en Java et des conseils pour jouer au golf dans toutes les langues peuvent être intéressants à lire. Encore une fois bienvenue, et profitez de votre séjour! :)
Kevin Cruijssen

Je pense qu'il y a encore quelques espaces que vous pouvez supprimer dans vos déclarations de variables. Bienvenue! :)
musicman523

@ musicman523 Merci, ouais corrigé. 194 pour l'instant :)
0x45

1
if(c[i]=='0'){j++;}peut encore être joué à if(c[i]==48)j++;-3 octets :) EDIT: Ou mieux encore: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}peut être for(;j<2&i>0;j+=c[i--]==48?1:0);à -8 octets.
Kevin Cruijssen

1
@ 0x45 Je crois que si vous changez le code de @ KevinCruijssen, for(;j<2&i>0;j+=c[--i]==48?1:0);cela devrait fonctionner. L'erreur vient de ila longueur de la chaîne, donc au départ, vous essayez d'indexer au-delà des limites du tableau. Si vous effectuez une pré-décrémentation (comme indiqué dans l'extrait mis à jour), la première fois que vous l'utiliserez, il y aura accès c[c.length-1]comme dans votre code d'origine.
Arnold Palmer


3

Code machine IA-32, 14 13 octets

Hexdump:

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

Liste de démontage:

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

Reçoit une entrée dans ecx; la sortie est en al. Renvoie 0 en cas d'erreur.

Tout d'abord, il inverse l'entrée, afin qu'il puisse utiliser les instructions de balayage de bits pour rechercher les bits définis. Il recherche le bit défini le moins significatif, le réinitialise, recherche à nouveau le bit défini le moins significatif et renvoie le résultat.

Si l'instruction de balayage de bits ne trouve aucun bit défini, la documentation Intel indique que la sortie n'est pas définie. Cependant, dans la pratique, tous les processeurs laissent le registre de destination inchangé dans ce cas (comme indiqué par Cody Gray, la documentation AMD décrit ce comportement comme obligatoire).

Donc, il y a les cas suivants:

  1. Pas de bits zéro (binaire 111 ... 1): ecx est mis à 0 par notet reste 0
  2. Un bit zéro: ecx est mis à 0 par btret reste 0 aprèsbsf
  3. Deux bits zéro: ecx est mis à la valeur appropriée par bsf

Seule la documentation d'Intel indique que les analyses de bits sur 0 ne sont pas définies. La documentation d'AMD indique explicitement que la destination est inchangée. Si vous voulez éviter ce comportement, vous devez normalement ajouter le préfixe REP pour obtenir LZCNT ou TZCNT, mais cela augmente le nombre d'octets, ce qui est naturellement indésirable pour le golf de code.
Cody Gray

1
En fait, vous faites trop de travail ici. Le défi ne vous oblige pas à faire la distinction entre le cas où il n'y a pas de bits zéro et le cas où il n'y a qu'un seul bit zéro. Il vous permet de retourner 0 (ou toute valeur négative) dans les deux cas. Ainsi, bien que le 1 octet SALC+ DECsoit extrêmement intelligent, vous pouvez raser un octet en utilisant simplement ce qu'il contient à ECXpartir de la deuxième BSFinstruction. La seule chose qui nécessite est un octet XCHGpour obtenir le résultat EAXafin qu'il puisse être retourné. En d'autres termes,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Gray

1
Voici un lien "essayez-le en ligne" pour ce qui précède . Puisque vous utilisez ECXcomme registre d'entrée, nous devons dire à GCC d'utiliser la convention d'appel fastcall.
Cody Gray

2

Dyalog APL, 20 octets

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

Utilise l'indexation 1, lance INDEX ERRORen cas d'absence de deuxième zéro.

Comment?

⍵⊤⍨- encoder en tant que

32⍴2 - chaîne binaire de longueur 32

- inverser

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

(⍳32)/⍨ - compresser avec la plage 1-32 (en laissant des index de zéros)

2⊃ - choisissez le deuxième élément


Vous pourriez économiser beaucoup d'octets en utilisant Where ( )
TwiNight

@TwiNight J'utilise dyalog 14
Uriel

TIO a Dyalog 16 si vous en avez besoin
TwiNight


1

Gelée , 12 octets

,4BUFḣ32¬TḊḢ

Un lien monadique, prenant un entier, utilisant l'option non signée et renvoyant le résultat indexé 1 (retourne 0 quand il n'en existe pas).

Essayez-le en ligne!

ou

32Ḷ2*|€n⁸TḊḢ

Essayez ça

Comment?

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

code machine x86_64, 34 32 octets

Je ne sais pas si c'est la bonne approche, beaucoup d'octets (il s'avère que ce n'est pas le cas ):

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

Essayez-le en ligne!

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

Merci @CodyGray pour les -2octets.


1
Faire une boucle sur tous les bits n'est probablement pas la bonne approche, que ce soit pour le golf par code ou pour le monde réel. La véritable percée sera d'utiliser l'une des instructions qui vous permettent de manipuler tous les 32 (ou 64) bits à la fois, commeBSF , BSR, POPCNT, BT, etc. Anatolyg a soumis une solution dans ce sens . Je n'ai pas encore déterminé s'il peut être battu. :-p
Cody Gray

1
Soit dit en passant, une astuce de golf de code potentiellement utile pour définir un registre sur -1 est de l'OR avec -1. Par exemple or ecx, -1,. C'est 3 octets, 1 octet de moins que XOR + NEG. Ce n'est pas un bon truc quand ne jouez pas au golf, car cela introduit une fausse dépendance en lecture sur le registre de destination, mais là, il vous suffit d'utiliser mov ecx, -1et de dépenser les 5 octets.
Cody Gray

1

8ème , 149 octets

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

Code commenté

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

Utilisation et sortie

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 octets

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

lit à partir de stdin; renvoie 0pour aucun deuxième zéro et le lieu autrement.

Essayez-le en ligne!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.