In quanti bit mi inserisco


52

Per qualsiasi 1 ≤ n ≤ 0xFFFFFFFFoutput intero positivo ( ) a 32 bit, il numero di bit necessari per rappresentare quell'intero.

Casi test

| n    | n in binary | bits needed |
|----------------------------------|
| 1    | 1           | 1           |
| 2    | 10          | 2           |
| 3    | 11          | 2           |
| 4    | 100         | 3           |
| 7    | 111         | 3           |
| 8    | 1000        | 4           |
| 15   | 1111        | 4           |
| 16   | 10000       | 5           |
| 128  | 10000000    | 8           |
| 341  | 101010101   | 9           |

4294967295 => 11111111111111111111111111111111 => 32

Quindi f(16)verrebbe stampato o restituito5

Questo è . Vince il codice più breve in byte


2
Questo è il soffitto del logaritmo in base 2.
orlp,

23
@orlp In realtà èfloor(log2(num))+1
Kritixi Lithos il

2
@KritixiLithos Giusto.
orlp,

3
Non importa, ho appena capito che il distinto è importante quando numè un potere di due.
Brian J,

11
Questa è una sfida banale con molte soluzioni banali. Esistono tuttavia anche soluzioni non banali. Per gli elettori: leggi la prima frase di questo meta post prima di valutare le funzioni integrate. (tratto umilmente da questo commento )
Kritixi Lithos il

Risposte:



35

JavaScript (ES6), 18 byte

f=n=>n&&1+f(n>>>1)
<input type=number min=0 step=1 value=8 oninput="O.value=f(this.value)">
<input id=O value=4 disabled>


Questa è una delle poche soluzioni non banali qui. Bella tattica!
Kritixi Lithos,

1
Dovrebbe essere n>>>1per supportare n > 0x7FFFFFFF?
Arnauld,

@Arnauld Hmm, non sapevo >>fallire così in nalto. Grazie.
Produzioni ETH il

Bello, il mio primo tentativo è statof=(a,b=1)=>a>1?f(a>>1,++b):b
Bassdrop Cumberwubwubwub il

28

x86 Assembly, 4 byte

Supponendo costante in EBX:

bsr eax,ebx
inc eax

EAX contiene il numero di bit necessari per Costante.

byte: ☼¢├@

esadecimale: ['0xf', '0xbd', '0xc3', '0x40']


2
Potresti includere un hexdump del codice assembly x86 compilato a 8 byte?
Loovjo,

Fatto così. E grazie, perché ho capito di aver fatto un errore. Ho aggiunto un "inc eax" per adattarsi alle regole. Ho perso un byte. :(
il

Oh caspita hai cambiato il mio post con una formattazione corretta. Grazie per averlo corretto!
il

2
A proposito, gli invii di Assembly possono presumere che l'input sia già memorizzato in un registro specifico , quindi penso che potresti rasare alcuni byte in quel modo.
Loovjo,

1
È consuetudine contare gli invii di assembly come numero di byte del codice macchina compilato anziché come codice sorgente del linguaggio assembly?
smls

18

Python , 14 byte

int.bit_length

Provalo online!


Funziona anche in Python 2.
vaultah,

1
Lo fa davvero. Di dimenticato Python 2 int era 64 bit di larghezza, non a 32 bit.
Dennis,

Python 3 bit_lengthè bit_length().
Dfernan,

2
@dfernan Questa non è una chiamata di funzione; è una funzione. Se n è un int , int.bit_length(n)e n.bit_length()fare esattamente la stessa cosa.
Dennis,

2
@dfernan int.bit_length(n)è una chiamata di funzione e quindi uno snippet che presuppone che l'input sia archiviato in una variabile. Ciò non è consentito dalle nostre regole, pertanto l'aggiunta (n)renderebbe non valida questa risposta. Tuttavia, int.bit_lengthrestituisce una funzione e può essere salvato in una variabile per un uso successivo. Questo è consentito per impostazione predefinita.
Dennis,

15

Labyrinth , 13 12 byte

 ?
_:
2/#(!@

Provalo online!

Spiegazione

Il programma semplicemente divide ripetutamente l'ingresso per 2 fino a quando è zero. Il numero di passaggi viene tenuto traccia duplicando il valore in ciascun passaggio. Una volta ridotto a zero, stampiamo la profondità della pila (meno 1).

Il programma inizia dal ?quale legge l'input. Il loop principale è quindi il blocco 2x2 sottostante, che va in senso antiorario:

:   Duplicate current value.
_2  Push 2.
/   Divide.

Una volta che il valore è zero dopo un'intera iterazione, viene eseguito il bit lineare alla fine:

#   Push stack depth.
(   Decrement.
!   Print.
@   Terminate.

5
Questa soluzione è completa - richiede input e fornisce la risposta e non utilizza alcuna funzione esistente per questo scopo specifico - calcola la risposta manualmente. Per me questo è più nello spirito del gioco della maggior parte delle altre risposte.
Johan,

15

C, 31 byte

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

... Poi ho pensato alla ricorsione. Dall'oscuro all'ovvio, e con un quarto della lunghezza calato.

Guardalo dal vivo su Coliru


C, 43 byte

c;
#define f(v)({for(c=0;v>=1l<<c;++c);c;})

La chiamata fcon un valore senza segno (ad es. f(42u)) "Restituirà" la sua lunghezza in bit. Funziona anche per 0u!

Ungolf e spiegato: (barre rovesciate omesse)

c;
#define f(v)
    ({ // GCC statement-expression

        // Increment c until (1 << c) >= v, i.e
        // that's enough bits to contain v.
        // Note the `l` to force long
        // arithmetic that won't overflow.
        for(c = 0; v >= 1l << c; ++c)
            ; // Empty for body

        c; // Return value
    })

Guardalo dal vivo su Coliru


OP garantisce n> = 1, quindi n?...:0non è necessario.
Fisico pazzo,

1
@MadPhysicist bene devo fermare la ricorsione da qualche parte, no;)
Quentin

OIC. Non ho letto attentamente, mi sento un idiota ora. Risposta chiara in entrambi i modi.
Mad Physicist,

@MadPhysicist non preoccuparti, grazie mille :)
Quentin,

Per la soluzione non ricorsiva che assume espressioni dell'istruzione gcc, credo che potresti essere stato propenso a usare anche l' #define f(n) ({64-__builtin_clzl(n);})approccio.
Moreaki

14

Mathematica, 9 byte

BitLength

In alternativa:

Floor@Log2@#+1&
#~IntegerLength~2&

14

Perl 6 , 7 byte

*.msb+1

Provalo

Spiegazione:

* lo fa diventare un lambda di qualunque codice e indica dove inserire l'input

.msb su un Int restituisce l'indice del bit più significativo (basato su 0)

+1viene combinato in lambda e ne aggiunge uno al risultato finale della chiamata .msb.



12

Retina , 56 37 byte

Questa soluzione funziona con tutti i valori di input richiesti.

Il problema più grande che Retina affronta in questa sfida è il fatto che le sue stringhe hanno una lunghezza massima di 2 ^ 30 caratteri, quindi il solito modo di trattare i numeri (rappresentazione unaria) non funziona con valori maggiori di 2 ^ 30.

Per risolvere questo problema ho adottato un approccio diverso, mantenendo una sorta di rappresentazione decimale dei numeri, ma in cui ogni cifra è scritta in modo unario (chiamerò questa rappresentazione digitale ). Ad esempio il numero 341sarebbe scritto come 111#1111#1#in digitunary. Con questa rappresentazione ora possiamo lavorare con numeri fino a 2^30/10cifre (~ cento milioni di cifre). È meno pratico di unario standard per l'aritmetica arbitraria, ma con un po 'di sforzo potremmo fare qualsiasi tipo di operazione.

NOTA: il digitunary in teoria potrebbe usare qualsiasi altra base (es. Binario 110sarebbe 1#1##in digitunary di base 2), ma poiché Retina ha builtin per convertire tra decimale e unario e nessun modo diretto per gestire altre basi, il decimale è probabilmente la base più gestibile.

L'algoritmo che ho usato sta facendo divisioni intere successive per due fino a raggiungere lo zero, il numero di divisioni che abbiamo creato è il numero di bit necessari per rappresentare questo numero.

Quindi, come possiamo dividere per due in digitunary? Ecco lo snippet Retina che lo fa:

(1*)(1?)\1#        We divide one digit, the first group captures the result, the second group captures the remainder
$1#$2$2$2$2$2      The result is put in place of the old number, the remainder passes to the next digit (so it is multiplied by 10) and is divided by two there -> 5 times the remainder goes to the next digit

Questa sostituzione è sufficiente per dividere un numero digitunary per 2, dobbiamo solo rimuovere eventuali 0,5 secondi dalla fine se il numero originale era dispari.

Quindi, ecco il codice completo, continuiamo a dividere per due finché non ci sono ancora cifre nel numero e mettiamo un letterale ndavanti alla stringa ad ogni iterazione: il numero di nalla fine è il risultato.

.                  |
$*1#               Convert to digitunary
{`^(.*1)           Loop:|
n$1                    add an 'n'
(1*)(1?)\1#            |
$1#$2$2$2$2$2          divide by 2
)`#1*$                 |
#                      erase leftovers
n                  Return the number of 'n's in the string

Provalo online!


Soluzione aggiornata, 37 byte

Grande refactoring con molte buone idee che hanno giocato a golf per circa un terzo della lunghezza, tutto grazie a Martin Ender!

L'idea principale è quella di usare _come nostro simbolo unario: in questo modo possiamo usare cifre regolari nella nostra stringa, purché le riconvertiamo in _s quando è necessario: questo ci consente di salvare molti byte sulla divisione e sull'inserimento di più cifre.

Ecco il codice:

<empty line>    |
#               put a # before each digit and at the end of the string 
{`\d            Loop:|
$*_                 Replace each digit with the corrisponding number of _
1`_                 |
n_                  Add an 'n' before the first _
__                  |
1                   Division by 2 (two _s become a 1)
_#                  |
#5                  Wherever there is a remainder, add 5 to the next digit
}`5$                |
                    Remove the final 5 you get when you divide odd numbers
n               Return the number of 'n's in the string

Provalo online!


1
Ho usato una forma numerica simile (ma l'ho chiamato Decimale con codice unario ), che è molto utile per l'aritmetica con Sed.
Toby Speight,

11

Rubino, 19 16 byte

->n{"%b"%n=~/$/}

Grazie Jordan per aver giocato a golf con 3 byte


È possibile salvare un byte con %: ->n{("%b"%n).size}.
Giordania,

3
Aspetta, questo è più breve: ->n{"%b"%n=~/$/}.
Giordania,

10

Jolf, 2 byte

lB

Converti semplicemente in binario e poi trova la lunghezza.



10

JavaScript ES6, 19 byte

a=>32-Math.clz32(a)

Math.clz32restituisce il numero di zero zero iniziali nella rappresentazione binaria a 32 bit di un numero. Quindi, per ottenere la quantità di bit necessari, tutto ciò che dobbiamo fare è sottrarre quel numero da 32

f=
  a=>32-Math.clz32(a)
  
pre {
    display: inline;
}
<input id=x type="number" oninput="y.innerHTML = f(x.value)" value=128><br>
<pre>Bits needed: <pre id=y>8</pre></pre>


2
L'alternativa a=>1+Math.log2(a)|0è anche di 19 byte.
Neil,

5
@Neil 1+...|0urla meno tilde ! a=>-~Math.log2(a)è il 18
edc65, il

@ edc65 Conto 17 ... ma sì, ero sicuro che mi mancava qualcosa, grazie per averlo segnalato.
Neil,

@Neil Sentiti libero di pubblicarlo come risposta separata. Utilizza un metodo diverso dalla mia risposta, quindi sarebbe ingiusto usare il tuo per un conteggio di byte ridotto
Bassdrop Cumberwubwubwub

10

strumenti bash / Unix, 16 byte

dc<<<2o$1n|wc -c

Salvalo in uno script e passa l'input come argomento. Verrà stampato il numero di bit richiesti per rappresentare quel numero in binario.

Ecco una spiegazione:

dc è una calcolatrice basata su stack. Il suo input, analizzato in token, è:

2 - Premere 2 sulla pila.

o - Estrarre un valore dallo stack (che è 2) e renderlo la base di output (quindi l'output è ora in binario).

Il valore dell'argomento nel programma bash ($ 1) - Sposta quell'argomento nello stack.

n: estrae un valore dallo stack (che è il numero di input) e lo stampa (in binario, perché quella è la base di output) senza newline finale.

Quindi il comando dc stampa il numero in binario.

L'output di dc viene reindirizzato al comando wc con l'opzione -c, che stampa il numero di caratteri nel suo input.

Il risultato finale è stampare il numero di cifre nella rappresentazione binaria dell'argomento.


Buona scelta della lingua, ma sarebbe ancora più interessante se includessi una spiegazione.
NH.

@NH Grazie. Ho aggiunto una spiegazione.
Mitchell Spector,

9

Fogli Google, 15 byte

Prende input dalla cella A1e output alla cella che contiene la formula

=Len(Dec2Bin(A1

o

=Int(1+Log(A1,2

o

=Int(Log(2*A1,2

Excel, 17 byte

Come sopra ma formattato per MS Excel

=Len(Dec2Bin(A1))

o

=Int(1+Log(A1,2))

o

=Int(Log(2*A1,2))



8

C #, 63 45 31 byte

Risparmiato 18 byte, grazie a Loovjo e TuukkaX

Salvato 14 byte, grazie a Grax

 b=>1+(int)System.Math.Log(b,2);

Usa, che un numero decimale n ha ⌊log2 (n) ⌋ + 1 bit, che è descritto in questa pagina:

Numero di bit in un intero decimale specifico

Un numero intero positivo n ha b bit quando 2 ^ (b-1) ≤ n ≤ 2 ^ b - 1. Ad esempio:

  • 29 ha 5 bit perché 16 ≤ 29 ≤ 31 o 2 ^ 4 ≤ 29 ≤ 2 ^ 5 - 1
  • 123 ha 7 bit perché 64 ≤ 123 ≤ 127 o 2 ^ 6 ≤ 123 ≤ 2 ^ 7 - 1
  • 967 ha 10 bit perché 512 ≤ 967 ≤ 1023 o 2 ^ 9 ≤ 967 ≤ 2 ^ 10 - 1

Per numeri più grandi, puoi consultare una tabella di poteri di due per trovare i poteri consecutivi che contengono il tuo numero.

Per capire perché funziona, pensiamo alle rappresentazioni binarie degli interi da 2 ^ 4 a 2 ^ 5 - 1, per esempio. Sono compresi tra 10000 e 11111, tutti i possibili valori a 5 bit.

Utilizzo dei logaritmi

Il metodo sopra può essere affermato in un altro modo: il numero di bit è l'esponente della potenza più piccola di due maggiore del tuo numero. Puoi affermarlo matematicamente come:

bspec = ⌊log2 (n) ⌋ + 1

Quella formula ha tre parti:

  • log2 (n) indica il logaritmo in base 2 di n, che è l'esponente a cui viene elevato 2 per ottenere n. Ad esempio, log2 (123) ≈ 6.9425145. La presenza di una parte frazionaria significa che n è tra potenze di due.

  • ⌊X⌋ è il piano di x, che è la parte intera di x. Ad esempio, ⌊6.9425145⌋ = 6. Puoi pensare a ⌊log2 (n) ⌋ come l'esponente della massima potenza di due nella rappresentazione binaria di n.

  • +1 porta l'esponente alla successiva potenza superiore di due. Puoi pensare a questo passaggio come alla contabilizzazione del 2 ^ 0 ° posto del tuo numero binario, che ti dà quindi il suo numero totale di bit. Per il nostro esempio, questo è 6 + 1 = 7. Potresti essere tentato di usare la funzione soffitto - ⌈x⌉, che è il numero intero più piccolo maggiore o uguale a x - per calcolare il numero di bit in quanto tale:

bspec = ⌈log2 (n) ⌉

Tuttavia, ciò fallisce quando n è una potenza di due.


Hai uno spazio extra lì dentro ...)+ 1)...-> ...)+1.... Inoltre, penso che tu possa restituire il valore direttamente invece di stamparlo.
Loovjo,

Puoi farlo scendere a 31 facendo b=>1+(int)System.Math.Log(b,2); La conversione int fornisce lo stesso output di Math.Floor e non hai bisogno dell'istruzione using se fai riferimento a System una sola volta.
Grax32,

6

C #, 32 byte

n=>Convert.ToString(n,2).Length;

Converte il parametro in una stringa binaria e restituisce la lunghezza della stringa.


4

Haskell, 20 byte

succ.floor.logBase 2

Composta una funzione che prende il logaritmo di base 2, piani e aggiunge 1.


4

Befunge-93 , 23 21 byte

&>2# /# :_1>+#<\#1_.@

Befunge è un linguaggio basato su griglia 2D (anche se sto usando solo una riga).

&                      take integer input
 >2# /# :_             until the top of the stack is zero, halve and duplicate it
          1>+#<\#1_    find the length of the stack
                   .@  output that length as an integer and terminate the program

Provalo online!


@JamesHolderness Grazie, ho pensato che potesse essere accorciato dato che aveva così tanti hash / spazi, ma non sono riuscito a capirlo.
JayDepp,





3

QBIC , 18 byte

:{~2^q>a|_Xq\q=q+1

È incredibile Mike! Ma come funziona?

:        Read input as integer 'a'
{        Start an infinite DO-LOOP
~2^q>a   If 2 to the power of q (which is 1 by default) is greater than a
|_Xq     Then quit, printing q
\q=q+1   Else, increment q
[LOOP is closed implicitly by QBIC]

3

Java 8, 34 27 byte

Per una volta, Java ha alcuni builtin utili! Ora abbiamo solo bisogno di nomi più brevi ...

x->x.toString(x,2).length()

Provalo online!

Ovviamente, puoi farlo senza builtin ( vedi la risposta di Snowman ), ma per un conteggio di byte più elevato.


3

Ottava, 19 byte

@(x)nnz(dec2bin(x))    % or
@(x)nnz(de2bi(x)+1)    % or
@(x)nnz(de2bi(x)<2)    % or
@(x)numel(de2bi(x))    % or
@(x)rows(de2bi(x'))

Octave ha due funzioni per convertire i numeri decimali in numeri binari.

dec2binconverte un numero in una stringa di caratteri 1e 0(valori ASCII 48e 49). La lunghezza della stringa sarà uguale al numero necessario di bit, se non diversamente specificato. Dal momento che i personaggi 1e 0sono non-zero, possiamo usare nnzper trovare il numero di elementi come questo: @(x)nnz(dec2bin(x)). Si tratta di 19 byte, quindi è legato con l'altra risposta Octave di Luis Mendo .

Possiamo fare di meglio usando de2bi?

de2biè una funzione che restituisce i numeri binari come vettore con i numeri 1e 0come numeri interi, non caratteri. de2biè ovviamente inferiore di due byte rispetto a dec2bin, ma non possiamo più utilizzarlo nnz. Siamo in grado di utilizzare nnz, se ci sia aggiungiamo 1a tutti gli elementi, o lo rende in un vettore logica con soli truevalori. @(x)nnz(de2bi(x)+1)e @(x)nnz(de2bi(x)<2)sono entrambi 19 byte. Utilizzando numelci darà anche 19 byte, @(x)numel(de2bi(x)).

rowsè un byte più corto di numel, ma de2birestituisce un vettore orizzontale, quindi deve essere trasposto. @(x)rows(de2bi(x)')solo così succede anche a 19 byte.



2

Retina ,  44  23 byte

Richiede troppa memoria per l'esecuzione di valori di input di grandi dimensioni. Converte in unario, quindi si divide ripetutamente per 2, contando quante volte fino a raggiungere zero. Il conteggio dei byte presuppone la codifica ISO 8859-1.

.*
$*
+`^(1+)1?\1
$1_
.

Provalo online


1
Non sono sicuro che questo sia valido. Questo non è un caso di "richiede più memoria di quella che probabilmente avrai" ma "richiede più memoria di quella che Retina stessa può gestire". In particolare, la conversione iniziale in unario fallirà per gli input di ordine 2 ^ 30 e superiori, a causa delle limitazioni nell'implementazione di Retina.
Martin Ender,

Se è valido, potrebbe essere abbreviato molto: tio.run/nexus/retina#@6@nxaWixaWdEKdhqK1paB9jyKViGM@l9/@/saUhAA
Martin Ender
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.