Encuentra el segundo cero

10

Desafío

Dado un número entero en formato de complemento a dos de 32 bits , devuelve el índice del segundo dígito cero menos significativo en la representación binaria, donde un índice de 0representa el bit menos significativo y un índice de 31representa el bit más significativo.

Si no hay un segundo cero, puede devolver 0, cualquier número negativo, cualquier valor falso o informar un error de una manera que tenga sentido en su idioma.

Puede usar la indexación 1 si lo prefiere, pero los casos de prueba a continuación utilizarán la indexación 0.

Puede usar enteros sin signo si lo prefiere; si lo hace, debe manejar enteros en el rango [0, 2^32). Si usa enteros con signo, debe manejar enteros en el rango [-2^31, 2^31). Los casos de prueba aquí usarán enteros con signo, pero tenga en cuenta que -x(con signo) es 2^32 - x(sin signo).

Casos de prueba

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

Puntuación

Este es el , por lo que gana la respuesta más corta en cada idioma.

musicman523
fuente
¿Podemos usar un entero sin signo en su lugar?
Leaky Nun
Sí, puede, siempre y cuando maneje enteros en el rango [0, 2^32).
musicman523
1
¿Estamos tomando el entero o la cadena 0b...como entrada?
TheLethalCoder
1
@JonathanAllan Supongo que no, ya que me corrigieron en mi respuesta de Jelly 2^32-1porque no se suponía que regresara 33.
Erik the Outgolfer
1
La respuesta de @JonathanAllan Erik es correcta. He actualizado la especificación desafío para reflejar que usted debe manejar enteros de 32 bits si usted decide tomar como con o sin signo
musicman523

Respuestas:

16

Python 2 , 45 bytes

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

Pruébalo en línea!

Utiliza indexación 0, números sin signo y arroja un error en ningún segundo cero.

Simplemente crea una lista de índices de bits no establecidos, de menor a mayor, y devuelve la segunda entrada.

Arnold Palmer
fuente
55
Bienvenido a PPCG! Bonito primer post!
Erik the Outgolfer
¡Gracias! Todavía soy muy nuevo en el truco del golf en Python, así que me alegra que este código no se haya eliminado de inmediato.
Arnold Palmer
Genial :) ¿qué pasa con n = 2147483647?
mdahmoune
@mdahmoune 2 ** 31-1 debería producir un error ya que su representación binaria en 32 bits es 0b01111111111111111111111111111111, que no tiene un segundo 0. A menos que me falte algo ...
Arnold Palmer
6

JavaScript (ES6), 34 bytes

Devuelve un índice basado en 0, o -1si no se encuentra un segundo cero.

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

Casos de prueba

Expresión alternativa

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

Versión recursiva, 42 bytes.

Devuelve un índice basado en 0, o falsesi no se encuentra un segundo cero.

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

¿Cómo?

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

Casos de prueba

Versión alternativa sugerida por Neil, 41 bytes

Devuelve un índice basado en 0 o arroja un error de recursión demasiado alto si no se encuentra un segundo cero.

f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Arnauld
fuente
Versión recursiva de 41 bytes:f=(n,c=1)=>n%2?1+f(~-n/2,c):c&&1+f(n/2,0)
Neil
5

Jalea , 7 bytes

|‘‘&~l2

Pruébalo en línea!

Emite algo que no está en el rango [1,31] si no hay el segundo cero. Esto incluye 32 33y (-inf+nanj). Supongo que tiene sentido.

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

jimmy23013
fuente
1
-inf+nanjNo pensé que eso pudiera existir
Luis Mendo
No genera (-inf+nanj)una entrada 2147483647que tenga una representación binaria de 31 1s, por lo tanto, no hay un segundo cero en notación con signo de 32 bits (es por eso que es mucho más corto que el mío y las respuestas de Erik).
Jonathan Allan
En realidad, cuando no se producen (-inf+nanj)?
Jonathan Allan
... ah creo que funcionó, ¿estás usando la opción firmada?
Jonathan Allan
4

Java, ... 194191186 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 para usar nombres de variables más pequeños y eliminar espacios en blanco
-25 Bytes, después de tomar variables aún más cortas y gracias a los consejos de @KevinCruijssen
-18 Bytes, más espacios en blanco, nombre de la función
-3 Bytes, gracias a @KevinCruijssen, acortando si la condición
-5 Bytes , Gracias a @Arnold Palmer, @KevinCruijssen, acortando el ciclo

Sin 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;
}
0x45
fuente
Bienvenido a PPCG! Hay bastantes cosas que puede jugar al golf: static se pueden quitar; if(n<0||n>o){return 0;}puede ser if(n<0|n>o)return 0;(en |lugar de ||y sin paréntesis); bs, bsaetc. pueden ser caracteres individuales (nunca use nombres de variables / métodos de varios bytes en code-golf); Se pueden combinar ints, como esto: int o=2^32-2,c=0,i=x.length,l=i-1;. Y hay algunas cosas más para el golf. Los consejos para jugar golf en Java y los consejos para jugar golf en todos los idiomas pueden ser interesantes de leer. Nuevamente bienvenido, y disfrute su estadía! :)
Kevin Cruijssen
Creo que todavía hay un par de espacios que puede eliminar en sus declaraciones de variables. ¡Bienvenidos! :)
musicman523
@ musicman523 Gracias, sí lo arregló. 194 por ahora :)
0x45
1
if(c[i]=='0'){j++;}todavía se puede jugar a if(c[i]==48)j++;-3 bytes :) EDITAR: O mejor aún: while(j<2&&i>0){i--;if(c[i]=='0'){j++;}}puede ser for(;j<2&i>0;j+=c[i--]==48?1:0);de -8 bytes.
Kevin Cruijssen
1
@ 0x45 Creo que si cambias el código de @ KevinCruijssen for(;j<2&i>0;j+=c[--i]==48?1:0);debería funcionar. El error proviene de iser la longitud de la cadena, por lo que inicialmente está tratando de indexar más allá de los límites de la matriz. Si hace un decremento previo (como se muestra en el fragmento actualizado), la primera vez que lo use accederá c[c.length-1]como en su código original.
Arnold Palmer
3

Código de máquina IA-32, 14 13 bytes

Hexdump:

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

Lista de desmontaje:

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

Recibe entrada en ecx; la salida está adentro al. Devuelve 0 por error.

En primer lugar, invierte la entrada, por lo que puede usar las instrucciones de escaneo de bits para buscar los bits establecidos. Busca el bit de configuración menos significativo, lo restablece, busca el bit de configuración menos significativo nuevamente y devuelve el resultado.

Si la instrucción de escaneo de bits no encuentra ningún bit establecido, la documentación de Intel dice que la salida no está definida. Sin embargo, en la práctica, todos los procesadores dejan el registro de destino sin cambios en este caso (como señaló Cody Gray, la documentación de AMD describe este comportamiento como obligatorio).

Entonces, hay los siguientes casos:

  1. Sin bits cero (binario 111 ... 1): ecx se establece en 0 por noty sigue siendo 0
  2. Un bit cero: ecx se establece en 0 por btry permanece 0 despuésbsf
  3. Dos bits cero: ecx se establece en el valor adecuado por bsf
anatolyg
fuente
Es solo la documentación de Intel que dice que los escaneos de bits en 0 no están definidos. La documentación de AMD documenta explícitamente que el destino no ha cambiado. Si desea evitar este comportamiento, normalmente agregaría el prefijo REP para obtener LZCNT o TZCNT, pero eso aumenta el recuento de bytes, lo que es naturalmente indeseable para el golf de código.
Cody Gray
1
Realmente estás haciendo demasiado trabajo aquí. El desafío no requiere que discrimines entre el caso donde no hay bits cero y el caso donde solo hay 1 bit cero. Le permite devolver 0 (o cualquier valor negativo) en ambos casos. Entonces, aunque el 1 byte SALC+ DECes extremadamente inteligente, puede eliminar un byte simplemente usando lo que esté en ECXla segunda BSFinstrucción. Lo único que requiere es un byte XCHGpara obtener el resultado EAXy poder devolverlo. En otras palabras,not ecx; bsf eax, ecx; btr ecx, eax; bsf ecx, ecx; xchg eax, ecx; ret
Cody Gray
1
Aquí hay un enlace "pruébelo en línea" para lo anterior . Como lo está utilizando ECXcomo registro de entrada, debemos decirle a GCC que use la convención de llamada de llamada rápida.
Cody Gray
2

Dyalog APL, 20 bytes

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

Utiliza indexación 1, tira INDEX ERRORen caso de que no haya segundo cero.

¿Cómo?

⍵⊤⍨- codificar como un

32⍴2 - cadena binaria de longitud 32

- marcha atrás

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

(⍳32)/⍨ - comprimir con el rango 1-32 (dejando índices de ceros)

2⊃ - elige el segundo elemento

Uriel
fuente
Podrías guardar muchos bytes usando Where ( )
TwiNight
@TwiNight uso dyalog 14
Uriel
TIO tiene Dyalog 16 si lo necesitas
TwiNight
1

Jalea , 13 bytes

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

Pruébalo en línea!

Utiliza la indexación 1, obtiene un entero sin signo como entrada. Devoluciones 0por no encontradas.

Erik el Outgolfer
fuente
Esto genera 33la entrada 4294967295( 2^32-1el equivalente sin signo de 32 bits de -1)
musicman523
@ musicman523 Hmm, algo huele a pescado ...
Erik the Outgolfer
1

Jalea , 12 bytes

,4BUFḣ32¬TḊḢ

Un enlace monádico, que toma un número entero, usa la opción sin signo y devuelve el resultado indexado 1 (devuelve 0 cuando no existe ninguno).

Pruébalo en línea!

o

32Ḷ2*|€n⁸TḊḢ

Trata eso

¿Cómo?

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
fuente
1

Código de máquina x86_64, 34 32 bytes

No estoy seguro de si este es el enfoque correcto, una gran cantidad de bytes (resulta que no lo es ):

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

Pruébalo en línea!

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

Gracias @CodyGray por -2bytes.

ბიმო
fuente
1
Recorrer todos los bits probablemente no sea el enfoque correcto, ya sea para el golf de código o para el mundo real. El verdadero avance va a utilizar una de las instrucciones que le permiten manipular los 32 (o 64) bits a la vez, como BSF, BSR, POPCNT, BT, etc. Anatolyg ha presentado una solución a lo largo de estas líneas . Todavía no he determinado si se puede vencer. :-p
Cody Gray
1
Por cierto, un truco de golf de código potencialmente útil para establecer un registro en -1 es OR o con -1. Por ejemplo, or ecx, -1. Eso es 3 bytes, 1 byte más corto que XOR + NEG. Este no es un buen truco cuando no juegas al golf porque introduce una dependencia de lectura falsa en el registro de destino, pero allí solo usarías mov ecx, -1y gastarías los 5 bytes.
Cody Gray
1

8o , 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:@

Código comentado

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

Uso y salida

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
Chaos Manor
fuente
0

R , 66 bytes

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

lee de stdin; regresa 0sin segundo cero y el lugar de lo contrario.

Pruébalo en línea!

Giuseppe
fuente