Quanto è pari un numero?


47

Gli antichi Greci chiamavano queste cose numeri singolarmente e doppiamente pari. Un esempio di un numero pari è pari a 14. Può essere diviso per 2 una volta e a quel punto è diventato un numero dispari (7), dopo di che non è più divisibile per 2. Un numero doppiamente pari è 20. Può essere diviso per 2 due volte, quindi diventa 5.

Il tuo compito è scrivere una funzione o un programma che accetta un numero intero come input e genera il numero di volte in cui è divisibile per 2 come numero intero, nel minor numero di byte possibile. L'input sarà un numero intero diverso da zero (qualsiasi valore positivo o negativo, entro i limiti della tua lingua).

Casi test:

14 -> 1

20 -> 2

94208 -> 12

7 -> 0

-4 -> 2

Vince la risposta con il minor numero di byte.

Suggerimento: prova a convertire il numero in base 2. Guarda cosa ti dice.


11
@AlexL. Potresti anche vederlo non è mai strano, così infinitamente uniforme. Potrei risparmiare qualche byte se è consentito un overflow dello stack;)
Geobits

1
The input will be a nonzero integerQuesto deve essere modificato dopo il tuo commento sullo zero come potenziale input?
trichoplax,

2
Questa è chiamata valutazione 2-adic o ordine 2-adic.
Paul,

7
A proposito, secondo Wikipedia, la valutazione p-adica di 0 è definita come infinito.
Paul,

3
Che domanda strana!
corsiKa

Risposte:


23

Gelatina , 4 byte

Æfċ2

Nell'ultima versione di Jelly, ÆEḢ(3 byte) funziona.

Æf      Calculate the prime factorization. On negative input, -1 appended to the end.
  ċ2    Count the 2s.

Provalo qui .


Questo funziona anche per input negativi.
lirtosiast,

1
@ThomasKwa Non credo che conta. Forse una meta domanda?
orlp,

ÆEḢ non va bene? In realtà emette 0 per i numeri dispari.
busukxuan,

@busukxuan Non funziona per ± 1.
lirtosiast,

1
@Tyzoid Jelly utilizza la propria codepage sull'interprete offline per impostazione predefinita, in cui un carattere è un byte.
lirtosiast,

93

codice macchina x86_64, 4 byte

L'istruzione BSF (bit scan forward) fa esattamente questo !

0x0f    0xbc    0xc7    0xc3

Nell'assembly in stile gcc, questo è:

    .globl  f
f:
    bsfl    %edi, %eax
    ret

L'input viene fornito nel registro EDI e restituito nel registro EAX secondo le convenzioni di chiamata standard a 64 bit .

A causa della codifica binaria del complemento a due, questo funziona per i numeri -ve e + ve.

Inoltre, nonostante la documentazione che dice "Se il contenuto dell'operando di origine è 0, il contenuto dell'operando di destinazione non è definito." , Trovo sulla mia macchina virtuale Ubuntu che l'output di f(0)è 0.

Istruzioni:

  • Salvare quanto sopra come evenness.se assemblare congcc -c evenness.s -o evenness.o
  • Salvare il seguente driver di test come evenness-main.ce compilare con gcc -c evenness-main.c -o evenness-main.o:
#include <stdio.h>

extern int f(int n);

int main (int argc, char **argv) {
    int i;

    int testcases[] = { 14, 20, 94208, 7, 0, -4 };

    for (i = 0; i < sizeof(testcases) / sizeof(testcases[0]); i++) {
        printf("%d, %d\n", testcases[i], f(testcases[i]));
    }

    return 0;
}

Poi:

  • link: gcc evenness-main.o evenness.o -o evenness
  • Correre: ./evenness

@FarazMasroor ha chiesto maggiori dettagli su come è stata ottenuta questa risposta.

Conosco meglio rispetto alle complessità dell'assembly x86, quindi in genere uso un compilatore per generare il codice assembly per me. So per esperienza che estensioni gcc come __builtin_ffs(), __builtin_ctz()e in__builtin_popcount() genere compilano e assemblano in 1 o 2 istruzioni su x86. Quindi ho iniziato con una funzione come:

int f(int n) {
    return __builtin_ctz(n);
}

Invece di usare la normale compilazione gcc fino al codice oggetto, puoi usare l' -Sopzione per compilare solo in assembly - gcc -S -c evenness.c. Questo dà un file assembly evenness.scome questo:

    .file   "evenness.c"
    .text
    .globl  f
    .type   f, @function
f:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    -4(%rbp), %eax
    rep bsfl    %eax, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   f, .-f
    .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
    .section    .note.GNU-stack,"",@progbits

Molto di questo può essere risolto. In particolare sappiamo che la convenzione di chiamata per funzioni con firma è semplice e piacevole: il parametro di input viene passato nel registro e il valore di ritorno viene restituito nel registro. Quindi possiamo prendere la maggior parte delle istruzioni: molte riguardano il salvataggio dei registri e l'impostazione di un nuovo stack frame. Non utilizziamo lo stack qui e utilizziamo solo il registro, quindi non è necessario preoccuparsi di altri registri. Questo lascia il codice assembly "golfed":int f(int n);EDIEAXEAX

    .globl  f
f:
    bsfl    %edi, %eax
    ret

Nota come sottolinea @zwol, puoi anche utilizzare una compilazione ottimizzata per ottenere un risultato simile. In particolare -Osproduce esattamente le istruzioni sopra (con alcune direttive addizionali sull'assemblatore che non producono alcun codice oggetto aggiuntivo).

Questo è ora assemblato con gcc -c evenness.s -o evenness.o, che può quindi essere collegato in un programma del driver di test come descritto sopra.

Esistono diversi modi per determinare il codice macchina corrispondente a questo assieme. Il mio preferito è usare il disasscomando disassembly gdb :

$ gdb ./evenness
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
Reading symbols from ./evenness...(no debugging symbols found)...done.
(gdb) disass /r f
Dump of assembler code for function f:
   0x00000000004005ae <+0>: 0f bc c7    bsf    %edi,%eax
   0x00000000004005b1 <+3>: c3  retq   
   0x00000000004005b2 <+4>: 66 2e 0f 1f 84 00 00 00 00 00   nopw   %cs:0x0(%rax,%rax,1)
   0x00000000004005bc <+14>:    0f 1f 40 00 nopl   0x0(%rax)
End of assembler dump.
(gdb) 

Quindi possiamo vedere che il codice macchina per l' bsfistruzione è 0f bc c7e per retè c3.


Non lo consideriamo come 2?
lirtosiast,

2
Come apprendo il codice di dump del linguaggio macchina / byte? Non riesco a trovare nulla online
Faraz Masroor,

1
Ciò non soddisfa la convenzione di chiamata C. Su x86-32, l'argomento viene passato nello stack; su x86-64, l'argomento viene passato in% rdi. Sembra funzionare solo all'interno del cablaggio di test perché il compilatore ha lasciato una copia non aggiornata dell'argomento in% eax. Si romperà se si compila il cablaggio evenness-main.ccon diverse impostazioni di ottimizzazione; per me si rompe con -O, -O2o -O3.
Anders Kaseorg,

1
@AndersKaseorg - grazie per averlo sottolineato. L'ho limitato solo a x86_64 ora, quindi l'input arriva in RDI.
Trauma digitale

3
"Inoltre, nonostante la documentazione che dice [...]" - Qualsiasi valore ottenuto concorda necessariamente con la documentazione. Ciò non esclude altri modelli di processori che danno un valore diverso dal tuo.
hvd,

25

Python, 25 byte

lambda n:len(bin(n&-n))-3

n & -n azzera tutto tranne il bit meno significativo, ad esempio questo:

100010101010100000101010000
            v
000000000000000000000010000

Siamo interessati al numero di zero finali, quindi lo convertiamo in una stringa binaria usando bin, che sarà per il numero sopra "0b10000". Dato che non ci interessa il 0b, né il 1, sottraggiamo 3 da quella lunghezza di stringhe.


dopo aver pubblicato la mia risposta ho pensato che la tua fosse molto intelligente, quindi ho provato a convertirla in Pyth e vedere se la tua era più corta della mia. Ha prodotto l. & Q_Q, usando log2 invece di len (bin (_)). Era della stessa lunghezza della mia risposta Pyth così come un'altra risposta Pyth, sembra che questo non ottenga più breve di 6 byte in Pyth ...
busukxuan

21

Pyth, 6 byte

/P.aQ2

Provalo qui .

 P.aQ         In the prime factorization of the absolute value of the input
/    2        count the number of 2s.

15

JavaScript (ES6), 18 byte

n=>Math.log2(n&-n)

4 byte in meno di 31-Math.clz32. Hah.


1
Oh wow, e solo recentemente ne ho saputo qualcosa Math.clz32...
Neil,

1
Accidenti stavo per pubblicare esattamente questo! +1
Cyoce,

13

JavaScript ES6, 22 19 byte

f=x=>x%2?0:f(x/2)+1

Sembra che la ricorsione sia la via più breve.


Oh nooo! Mi hai battuto! Ben fatto :) +1
Connor Bell,

6

Pyth, 8 byte

lec.BQ\1
     Q    autoinitialized to eval(input())
   .B     convert to binary string
  c   \1  split on "1", returning an array of runs of 0s
 e        get the last run of 0s, or empty string if number ends with 1
l         take the length

Ad esempio, la rappresentazione binaria di 94208è:

10111000000000000

Dopo aver diviso su se 1aver preso l'ultimo elemento dell'array risultante, questo diventa:

000000000000

Sono 12 zero, quindi è "12-anche pari".

Questo funziona perché x / 2è essenzialmente x >> 1— vale a dire, un diritto di spostamento dei bit di 1. Pertanto, un numero è divisibile per 2 solo quando lo è LSB 0(proprio come come un numero decimale è divisibile per 10 quando è l'ultima cifra 0).


6

05AB1E , 4 5 byte

Ora supporta numeri negativi. Codice:

Äb1¡g

Provalo online!

Spiegazione:

Ä      # Abs(input)
 b     # Convert the number to binary
  1¡   # Split on 1's
    g  # Take the length of the last element

Utilizza la codifica CP-1252.


6

Pyth, 6 byte

x_.BQ1

Fondamentalmente solo

convert2BinString(evaluatedInput())[::-1].index("1")

6

MATL , 5 byte

Yf2=s

Questo funziona per tutti i numeri interi.

Provalo online!

Yf      % implicit input. Compute (repeated) prime factors. For negative input
        % it computes the prime factors of the absolute value, except that for
        % -1 it produces an empty array instead of a single 1
2=s     % count occurrences of "2" in the array of prime factors

"E ora, per qualcosa di completamente diverso ..."
Becher

6

C, 36 (28) byte

int f(int n){return n&1?0:f(n/2)+1;}

(Non è stato testato l'argomento zero come argomento diverso da zero.)

Aggiornamento (in risposta al commento) : se consentiamo dichiarazioni di funzioni in stile K&R, possiamo avere una versione a 28 byte:

f(n){return n&1?0:f(n/2)+1;}

In questo caso, facciamo affidamento sul fatto che il compilatore predefinisce entrambi ne il tipo restituito di fa int. Questo modulo genera un avviso con C99 e non viene compilato come codice C ++ valido.


Se cambi int n-> nè ancora un codice C valido e taglia 4 caratteri.
Josh,

Buon punto. Stavo per dire che questo innesca almeno un avvertimento con C99, ma omette anche il tipo restituito. Ed entrambi generano errori in C ++. Quindi sto cambiando la mia risposta in modo appropriato.
Viktor Toth,

5

Java 7, 39 o forse 44 byte

int s(int a){return a%2!=0?0:s(a/2)+1;}

int s(int a){return a%2!=0|a==0?0:s(a/2)+1;}

Yay ricorsione! Ho dovuto usare un confronto !=anziché un confronto più breve in modo che non traboccasse di input negativi, ma a parte questo è piuttosto semplice. Se è dispari, invia uno zero. Se pari, aggiungine uno e fallo di nuovo.

Esistono due versioni perché in questo momento l'output per zero è sconosciuto. Il primo ricorre fino a quando lo stack non trabocca e non emette nulla, perché 0 è infinitamente uniforme. Il secondo emette un risultato piacevole, sicuro, ma probabilmente non matematicamente rigoroso.


4

JavaScript (ES6), 20 byte 19 byte.

f=x=>~x%2&&1+f(x/2)

Questa è una porta della soluzione Haskell di @nimi a JavaScript. Utilizza le proprietà "cortocircuito" di &&cui restituisce il lato sinistro se è falso (che in questo caso lo è -0) oppure restituisce il lato destro. Per implementare odd x = 0, quindi, creiamo il lato sinistro 1 - (x % 2)che bolle 0attraverso il &&, altrimenti facciamo ricorso 1 + f(x / 2).

La rasatura di 1 - (x % 2)as (~x) % 2è dovuta a @Neil di seguito, e ha la strana proprietà che provoca l'emissione della funzione sopra -0per piccoli numeri dispari. Questo valore è una peculiarità della decisione di JS secondo cui gli interi sono doppi IEEE754; questo sistema ha un sistema separato +0e -0che sono inseriti in JavaScript in modo speciale l' ===uno con l'altro. L' ~operatore calcola l'inversione bit per bit con segno a 32 bit per il numero, che per numeri dispari piccoli sarà un numero pari negativo. (Il numero positivo Math.pow(2, 31) + 1per esempio produce 0piuttosto che -0.) La strana restrizione agli interi con segno a 32 bit non ha altri effetti; in particolare non influisce sulla correttezza.


~x&1è un byte più corto di 1-x%2.
Neil,

@Neil Molto bello. Ha una proprietà un po 'controintuitiva ma la prenderò comunque.
CR Drost,

4

Perl 6, 23 18 byte

{+($_,*/2...^*%2)}

uso

> my &f = {+($_,*/2...^*%2)}
-> ;; $_? is raw { #`(Block|117104200) ... }
> f(14)
1
> f(20)
2
> f(94208)
12
> f(7)
0
> f(-4)
2

4

Ruby 24 byte

Il mio primo invio di codice golf (yey!)

("%b"%$*[0])[/0*$/].size

Come sono arrivato qui :

Per prima cosa volevo ottenere un codice che soddisfacesse effettivamente le specifiche per risolvere il problema, quindi ho creato il metodo indipendentemente dal numero di byte:

def how_even(x, times=1)
  half = x / 2
  if half.even?
    how_even(half, times+1)
  else
    times
  end
end

con questa conoscenza ho riclassificato la funzione in un ciclo while e $*ho aggiunto (ARGV) come input e i come conteggio di quante volte il numero è stato dimezzato prima che diventi dispari.

x=$*[0];i=1;while(x=x/2)%2<1;i+=1;end;i

Ne ero abbastanza orgoglioso e quasi l'ho presentato prima che mi sembrasse che tutta questa divisione per due mi suonasse un po 'binaria, essendo un ingegnere informatico ma non tanto un informatico, non era la prima cosa che mi è venuta in mente.

Quindi ho raccolto alcuni risultati su come apparivano i valori di input in binario:

input      in binary      result
---------------------------------
   14               1110   1
   20              10100   2
94208  10111000000000000  12

Ho notato che il risultato è stato il numero di posizioni a sinistra che dobbiamo attraversare prima che il numero diventi dispari.

Facendo alcune semplici manipolazioni della stringa ho diviso la stringa sull'ultima occorrenza di 1 e ho contato la lunghezza degli 0 rimanenti:

("%b"%$*[0])[/0*$/].size

usando la ("%b" % x)formattazione per trasformare un numero in binario e String # slice per tagliare la mia stringa.

Ho imparato alcune cose sul rubino in questa ricerca e non vedo l'ora di vedere altri golf presto!


2
Benvenuti in Puzzle di programmazione e scambio di code golf stack. Questa è un'ottima risposta; Mi piace molto la spiegazione. +1! Se vuoi più sfide di code-golf, fai clic sul tag code-golf . Non vedo l'ora di vedere altre tue risposte.
wizzwizz4,

1
Sentiti libero di farmi delle domande che hai. Digita @wizzwizz4all'inizio di un commento per rispondermi. (Funziona con tutti i nomi utente!)
wizzwizz4,

4

J, 6 byte

1&q:@|

Spiegazione:

     |    absolute value
1&q:      exponent of 2 in the prime factorization

4

C, 37 byte

f(int x){return x?x&1?0:1+f(x/2):0;} Controlla ricorsivamente l'ultimo bit fino a quando non è uno 0.


Inoltre, c'è f(int n){return __builtin_ctz(n);}se sei disposto a usare le estensioni gcc. O addirittura#define f __builtin_ctz
Digital Trauma,

Rimuovi int . È implicito, proprio come il tipo restituito.
Luser droog

@luserdroog, vuoi dire f(n){...}? GCC non lo compilerà. Non sono un esperto di C, ma una rapida ricerca rivela che forse questa funzione è stata rimossa nelle versioni più recenti di C. Quindi forse si compila con i flag appropriati?
Andy Soffer,

@AndySoffer vedo. Forse -ansio -gnu99? So di averlo fatto funzionare. Ho scritto una risposta suggerimenti a riguardo!
Luser droog

3

Haskell, 28 byte

f x|odd x=0|1<2=1+f(div x 2)

Esempio di utilizzo: f 94208-> 12.

Se il numero è dispari, il risultato è 0, altrimenti 1più una chiamata ricorsiva con metà del numero.


div x 2? Perché no x/2?
CalculatorFeline

@CatsAreFluffy: Haskell ha un sistema di tipi molto rigido. divè divisione intera, divisione in /virgola mobile.
nimi,

3

Befunge, 20

&:2%#|_\1+\2/#
   @.<

L'esecuzione del codice continua a spostarsi a destra e ad avvolgersi attorno al secondo carattere della prima riga (grazie al trailing #) fino alle 2%uscite 1, che provoca il _passaggio da sinistra a sinistra, quindi |verso l'alto, che si avvolge attorno alla <seconda riga, quali uscite e uscite. Incrementiamo l'elemento secondo in cima alla pila ogni volta attraverso il ciclo, quindi dividiamo la parte superiore per 2.


3

Retina ,29 17

+`\b(1+)\1$
;$1
;

Provalo online!

2 byte salvati grazie a Martin!

Accetta un input unario. Questo corrisponde ripetutamente al maggior numero di 1s possibile in modo tale che quel numero di 1s corrisponda esattamente al resto dei 1s nel numero. Ogni volta che lo fa, antepone ;a alla stringa. Alla fine, contiamo il numero di ;s nella stringa.

Se si desidera un input decimale, aggiungere:

\d+
$0$*1

all'inizio del programma.


3

Jolf, 6 byte

Provalo qui!

Zlm)j2
Zl   2  count the number occurrences of 2 in
  m)j   the prime factorization of j (input)

Piuttosto semplice ... Complimenti a ETHProductions per aver espulso Jolf con la versione che dovrebbe davvero funzionare!


1
6 byte sembra essere il numero magico per questa sfida
Cyoce,


3

6502 linguaggio macchina, 7 byte

Per trovare il valore del posto del 1 bit meno significativo del valore diverso da zero nell'accumulatore, lasciando il risultato nel registro X:

A2 FF E8 4A 90 FC 60

Per eseguirlo sul simulatore 6502 su e-tradition.net , aggiungere il prefisso A9seguito da un numero intero a 8 bit.

Questo disassembla a quanto segue:

count_trailing_zeroes:
    ldx #$FF
loop:
    inx
    lsr a     ; set carry to 0 iff A divisible by 2, then divide by 2 rounding down
    bcc loop  ; keep looping if A was divisible by 2
    rts       ; return with result in X

Ciò equivale alla seguente C, tranne per il fatto che C richiede intdi essere almeno a 16 bit:

unsigned int count_trailing_zeroes(int signed_a) {
    unsigned int carry;
    unsigned int a = signed_a;  // cast to unsigned makes shift well-defined
    unsigned int x = UINT_MAX;
    do {
        x += 1;
        carry = a & 1;
        a >>= 1;
    } while (carry == 0);
    return x;
}

Lo stesso funziona su un 65816, presupponendo MX = 01 (accumulatore a 16 bit, indice a 8 bit) ed è equivalente allo snippet C sopra.


2

Brachylog , 27 15 byte

$pA:2xlL,Al-L=.

Spiegazione

$pA             § Unify A with the list of prime factors of the input
   :2x          § Remove all occurences of 2 in A
      lL,       § L is the length of A minus all the 2s
         Al-L=. § Unify the output with the length of A minus L

2

CJam, 8 byte

rizmf2e=

Leggi intero, valore assoluto, fattore primo, conta due.


2

JavaScript ES6, 36 38 byte

Golfato di due byte grazie a @ETHproductions

Risposta abbastanza noiosa, ma fa il lavoro. In realtà potrebbe essere troppo simile a un'altra risposta, se aggiunge le modifiche suggerite, rimuoverò la mia.

b=>{for(c=0;b%2-1;c++)b/=2;alert(c)}

Per eseguirlo, assegnalo a una variabile ( a=>{for...) in quanto è una funzione anonima, quindi chiamalo con a(100).


Bella risposta! b%2==0può essere modificato in b%2-1e c++può essere spostato nell'ultima parte fordell'istruzione. Penso che funzionerebbe anche:b=>eval("for(c=0;b%2-1;b/=2)++c")
ETHproductions

@ETHproductions Così può! Bella cattura :)
Connor Bell,

Un altro byte: b%2-1=> ~b&1Inoltre, penso che questo fallisca nell'input di 0, che può essere risolto conb&&~b&1
ETHproductions

Congelato il mio computer test questo su un numero negativo. b%2-1il controllo fallisce per i numeri dispari negativi.
Patrick Roberts,

2

ES6, 22 byte

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

Restituisce -1 se si passa 0.


Ah, carino. Mi sono dimenticato di clz32: P
Conor O'Brien,

2

DUP , 20 byte

[$2/%0=[2/f;!1+.][0]?]f:

Try it here!

Convertito in ricorsione, l'output è ora il numero più alto nello stack. Uso:

94208[2/\0=[f;!1+][0]?]f:f;!

Spiegazione

[                ]f: {save lambda to f}
 2/\0=               {top of stack /2, check if remainder is 0}
      [     ][ ]?    {conditional}
       f;!1+         {if so, then do f(top of stack)+1}
              0      {otherwise, push 0}

2

Japt, 9 5 byte

¢w b1

Provalo online!

La versione precedente avrebbe dovuto essere di cinque byte, ma questa effettivamente funziona.

Come funziona

       // Implicit: U = input integer
¢      // Take the binary representation of U.
w      // Reverse.
b1     // Find the first index of a "1" in this string.
       // Implicit output

2

C, 44 40 38 36 byte

2 byte di sconto grazie @JohnWHSmith . 2 byte di sconto grazie @luserdroog .

a;f(n){for(;~n&1;n/=2)a++;return a;}

Prova dal vivo su ideone .


Potresti riuscire a togliere 1 byte sostituendo il costoso !(n%2)con un bel po ' ~n&1.
John WH Smith,

@JohnWHSmith. È stato carino!! Grazie
rimosso il

Rimuovi il =0. I globi vengono inizializzati implicitamente su 0.
Luser droog

@luserdroog. Grazie, non lo sapevo.
rimosso il

Correggimi se sbaglio, ma poiché questa funzione utilizza la variabile globale a, non è garantito che funzioni solo la prima volta che viene chiamato? Non sapevo che fosse permesso.
Patrick Roberts,
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.