Dalam berapa banyak bit yang saya cocok


52

Untuk setiap bilangan bulat 32-bit positif ( 1 ≤ n ≤ 0xFFFFFFFF) menghasilkan jumlah bit yang diperlukan untuk mewakili bilangan bulat itu.

Uji kasus

| 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

Jadi f(16)akan mencetak atau kembali5

Ini adalah . Kode terpendek dalam byte menang


2
Ini adalah langit-langit dari basis-2 logaritma.
orlp

23
@ orlp Sebenarnyafloor(log2(num))+1
Kritixi Lithos

2
@KritixiLithos Benar.
orlp

3
Nevermind, baru menyadari bahwa perbedaan itu penting ketika numkekuatan dua.
Brian J

11
Ini adalah tantangan sepele dengan banyak solusi sepele. Namun ada beberapa solusi non-sepele juga. Kepada para pemilih: Harap baca kalimat pertama dari posting meta ini sebelum meningkatkan fungsi bawaan. (diambil dari komentar ini dengan rendah hati )
Kritixi Lithos

Jawaban:



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>


Ini adalah salah satu dari sedikit solusi non-sepele di sini. Taktik yang bagus!
Kritixi Lithos

1
Haruskah itu n>>>1untuk mendukung n > 0x7FFFFFFF?
Arnauld

@Arnauld Hmm, tidak tahu >>gagal pada nsetinggi itu. Terima kasih.
ETHproduk

Bagus, upaya pertama saya adalahf=(a,b=1)=>a>1?f(a>>1,++b):b
Bassdrop Cumberwubwubwub

28

x86 Assembly, 4 byte

Dengan asumsi Constant dalam EBX:

bsr eax,ebx
inc eax

EAX berisi jumlah bit yang diperlukan untuk Constant.

Bytes: ☼¢├@

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


2
Bisakah Anda menyertakan hexdump dari kode Majelis x86 yang disusun 8 byte yang sebenarnya?
Loovjo

Melakukannya. Dan terima kasih, karena saya sadar saya melakukan kesalahan. Saya menambahkan "inc eax" agar sesuai dengan aturan. Saya kehilangan satu byte. :(
z0rberg

Oh wow, Anda mengubah pos saya ke pemformatan yang tepat. Terima kasih telah memperbaikinya!
z0rberg

2
Ngomong-ngomong, kiriman Majelis dapat mengasumsikan bahwa input sudah disimpan dalam register tertentu , jadi saya pikir Anda bisa memotong beberapa byte dengan cara itu.
Loovjo

1
Apakah lazim untuk menghitung pengiriman perakitan sebagai jumlah byte dari kode mesin yang dikompilasi daripada kode sumber bahasa assembly?
sml

18

Python , 14 byte

int.bit_length

Cobalah online!


Ia bekerja di Python 2 juga.
vaultah

1
Memang benar. Int Forgot Python 2 adalah lebar 64 bit, bukan 32 bit.
Dennis

Python 3 bit_lengthadalah bit_length().
dfernan

2
@dfernan Ini bukan panggilan fungsi; itu sebuah fungsi. Jika n adalah int , int.bit_length(n)dan n.bit_length()lakukan hal yang persis sama.
Dennis

2
@dfernan int.bit_length(n)adalah panggilan fungsi , dan dengan demikian potongan yang mengasumsikan input disimpan dalam variabel. Ini tidak diizinkan oleh aturan kami, jadi menambahkan (n)akan membuat jawaban ini tidak valid. Namun, int.bit_lengthmengevaluasi ke suatu fungsi dan dapat disimpan dalam variabel untuk digunakan nanti. Ini diizinkan secara default.
Dennis

15

Labirin , 13 12 byte

 ?
_:
2/#(!@

Cobalah online!

Penjelasan

Program hanya berulang kali membagi input dengan 2 hingga nol. Jumlah langkah dilacak dengan menduplikasi nilai pada setiap langkah. Setelah dikurangi menjadi nol, kami mencetak kedalaman tumpukan (minus 1).

Program dimulai dari ?yang membaca input. Loop utama kemudian blok 2x2 di bawah ini, berlawanan arah jarum jam:

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

Setelah nilainya nol setelah iterasi penuh, bit linier pada akhirnya dijalankan:

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

5
Solusi ini selesai - dibutuhkan input dan memberikan jawaban, dan tidak memanfaatkan fungsi apa pun yang ada untuk tujuan khusus ini - solusi ini menghitung jawabannya secara manual. Bagi saya ini lebih dalam semangat permainan daripada jawaban lainnya.
Johan

15

C, 31 byte

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

... Lalu aku memikirkan rekursi. Dari yang tidak jelas menjadi jelas, dan dengan seperempat panjang jatuh.

Lihat langsung di Coliru


C, 43 byte

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

Memanggil fdengan nilai yang tidak ditandatangani (mis. f(42u)) Akan "mengembalikan" panjang bitnya. Bahkan berhasil 0u!

Tidak diikat dan dijelaskan: (garis miring terbalik dihilangkan)

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

Lihat langsung di Coliru


Jaminan OP n> = 1, jadi n?...:0tidak perlu.
Fisikawan Gila

1
@ MadPhysicist yah saya harus menghentikan rekursi di suatu tempat, bukan saya;)
Quentin

OKI. Tidak membaca dengan hati-hati, merasa seperti orang tolol sekarang. Pokoknya jawab dengan rapi.
Fisikawan Gila

@MadPhysicist jangan khawatir, terima kasih banyak :)
Quentin

Untuk solusi non-rekursif dengan asumsi ekspresi pernyataan gcc, saya rasa Anda mungkin cenderung menggunakan #define f(n) ({64-__builtin_clzl(n);})pendekatan ini juga.
Moreaki

14

Mathematica, 9 byte

BitLength

Kalau tidak:

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

14

Perl 6 , 7 byte

*.msb+1

Cobalah

Penjelasan:

* membuatnya menjadi lambda WhateverCode, dan menunjukkan di mana harus memasukkan input

.msb pada Int mengembalikan indeks bit paling signifikan (berbasis 0)

+1digabungkan ke dalam lambda, dan menambahkan satu ke hasil panggilan akhirnya .msb.



12

Retina , 56 37 byte

Solusi ini bekerja dengan semua nilai input yang diperlukan.

Masalah terbesar yang dihadapi Retina dalam tantangan ini adalah kenyataan bahwa string-nya memiliki panjang maksimum 2 ^ 30 karakter, jadi cara biasa menangani angka (representasi unary) tidak bekerja dengan nilai lebih besar dari 2 ^ 30.

Untuk mengatasi masalah ini saya mengadopsi pendekatan yang berbeda, menjaga semacam representasi angka desimal, tetapi di mana setiap digit ditulis dalam unary (Saya akan menyebut digitunary representasi ini ). Misalnya angka 341akan ditulis 111#1111#1#dalam digitunary. Dengan representasi ini sekarang kita dapat bekerja dengan jumlah hingga 2^30/10digit (~ seratus juta digit). Ini kurang praktis daripada standar unary untuk aritmatika sewenang-wenang, tetapi dengan sedikit usaha kita bisa melakukan segala jenis operasi.

CATATAN: digitunary dalam teori dapat menggunakan basis lain (misalnya biner 110akan menjadi 1#1##basis 2 digitunary), tetapi karena Retina memiliki builtin untuk mengkonversi antara desimal dan unary dan tidak ada cara langsung untuk berurusan dengan basis lain, desimal mungkin merupakan basis yang paling dapat dikelola.

Algoritma yang saya gunakan adalah membuat pembagian integer berturut-turut sebanyak dua hingga kita mencapai nol, jumlah divisi yang kami buat adalah jumlah bit yang diperlukan untuk mewakili angka ini.

Jadi, bagaimana kita membagi dua menjadi digitunary? Berikut cuplikan Retina yang melakukannya:

(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

Penggantian ini cukup untuk membagi angka digital dengan 2, kita hanya perlu menghapus 0,5 mungkin dari akhir jika nomor aslinya ganjil.

Jadi, inilah kode lengkapnya, kita terus membaginya dengan dua sampai masih ada angka dalam bilangan, dan menempatkan literal ndi depan string pada setiap iterasi: jumlah npada akhirnya adalah hasilnya.

.                  |
$*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

Cobalah online!


Solusi yang diperbarui, 37 byte

Refactoring besar dengan banyak ide bagus yang bermain golf sekitar sepertiga panjangnya, semua berkat Martin Ender!

Gagasan utamanya adalah untuk digunakan _sebagai simbol unary kita: dengan cara ini kita dapat menggunakan digit reguler dalam string kita, selama kita mengubahnya kembali menjadi _s ketika diperlukan: ini memungkinkan kita menyimpan banyak byte pada pembagian dan penyisipan banyak digit.

Ini kodenya:

<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

Cobalah online!


1
Saya telah menggunakan bentuk numerik yang serupa (tetapi menyebutnya Unary-Coded Decimal ), yang cukup berguna untuk berhitung dengan Sed.
Toby Speight

11

Ruby, 19 16 byte

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

Terima kasih Jordan untuk bermain golf 3 byte


Anda dapat menyimpan byte dengan %: ->n{("%b"%n).size}.
Jordan

3
Tunggu, ini lebih pendek: ->n{"%b"%n=~/$/}.
Jordan



10

JavaScript ES6, 19 byte

a=>32-Math.clz32(a)

Math.clz32mengembalikan jumlah bit nol terkemuka dalam representasi biner 32-bit dari suatu angka. Jadi untuk mendapatkan jumlah bit yang dibutuhkan, yang perlu kita lakukan adalah mengurangi jumlah itu dari 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
Alternatifnya a=>1+Math.log2(a)|0juga 19 byte.
Neil

5
@Neil 1+...|0menjerit minus tilde ! a=>-~Math.log2(a)adalah 18
edc65

@ edc65 Saya hitung 17 ... tapi ya, saya yakin saya kehilangan sesuatu, terima kasih telah menunjukkannya.
Neil

@Neil Jangan ragu untuk mempostingnya sebagai jawaban terpisah. Ini menggunakan metode yang berbeda dari jawaban saya sehingga akan terasa tidak adil untuk menggunakan milik Anda untuk jumlah byte yang dikurangi
Bassdrop Cumberwubwubwub

10

bash / alat Unix, 16 byte

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

Simpan ini dalam skrip, dan berikan input sebagai argumen. Jumlah bit yang diperlukan untuk mewakili angka itu dalam biner akan dicetak.

Berikut penjelasannya:

dc adalah kalkulator berbasis tumpukan. Inputnya, diuraikan menjadi token, adalah:

2 - Tekan 2 pada tumpukan.

o - Pop nilai dari stack (yang 2) dan menjadikannya basis output (jadi output sekarang dalam biner).

Nilai argumen untuk program bash ($ 1) - Dorong argumen itu di stack.

n - Pop nilai dari stack (yang merupakan nomor input) dan cetak (dalam biner, karena itulah basis output) tanpa baris baru.

Jadi perintah dc mencetak angka dalam biner.

Output dari dc disalurkan ke perintah wc dengan opsi -c, yang mencetak jumlah karakter dalam inputnya.

Hasil akhirnya adalah mencetak jumlah digit dalam representasi biner dari argumen tersebut.


Pilihan bahasa yang bagus, tetapi akan lebih keren jika Anda menyertakan penjelasan.
NH.

@NH, terima kasih. Saya telah menambahkan penjelasan.
Mitchell Spector

9

Google Sheets, 15 Bytes

Membawa input dari sel A1dan output ke sel yang menyimpan formula

=Len(Dec2Bin(A1

atau

=Int(1+Log(A1,2

atau

=Int(Log(2*A1,2

Excel, 17 Bytes

Sama seperti di atas tetapi diformat untuk MS Excel

=Len(Dec2Bin(A1))

atau

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

atau

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



8

C #, 63 45 31 byte

Disimpan 18 byte, terima kasih kepada Loovjo, dan TuukkaX

Disimpan 14 byte, terima kasih kepada Grax

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

Ia menggunakan, bahwa angka desimal n memiliki ⌊log2 (n) ⌋ + 1 bit, yang dijelaskan pada halaman ini :

Jumlah Bit dalam Integer Desimal Tertentu

Bilangan bulat positif n memiliki b bit ketika 2 ^ (b-1) ≤ n ≤ 2 ^ b - 1. Misalnya:

  • 29 memiliki 5 bit karena 16 ≤ 29 ≤ 31, atau 2 ^ 4 ≤ 29 ≤ 2 ^ 5 - 1
  • 123 memiliki 7 bit karena 64 ≤ 123 ≤ 127, atau 2 ^ 6 ≤ 123 ≤ 2 ^ 7 - 1
  • 967 memiliki 10 bit karena 512 ≤ 967 ≤ 1023, atau 2 ^ 9 ≤ 967 ≤ 2 ^ 10 - 1

Untuk angka yang lebih besar, Anda bisa berkonsultasi dengan tabel dua kekuatan untuk menemukan kekuatan berturut-turut yang berisi nomor Anda.

Untuk melihat mengapa ini bekerja, pikirkan representasi biner dari bilangan bulat 2 ^ 4 hingga 2 ^ 5 - 1, misalnya. Mereka adalah 10000 hingga 11111, semua nilai 5-bit yang memungkinkan.

Menggunakan Logaritma

Metode di atas dapat dinyatakan dengan cara lain: jumlah bit adalah eksponen dari kekuatan terkecil dua lebih besar dari jumlah Anda. Anda dapat menyatakan bahwa secara matematis sebagai:

bspec = ⌊log2 (n) ⌋ + 1

Formula itu memiliki tiga bagian:

  • log2 (n) berarti logaritma pada basis 2 dari n, yang merupakan eksponen yang dinaikkan 2 untuk mendapatkan n. Misalnya, log2 (123) ≈ 6.9425145. Kehadiran bagian pecahan berarti n adalah di antara kekuatan dua.

  • ⌊X⌋ adalah lantai x, yang merupakan bagian integer dari x. Sebagai contoh, ⌊6.9425145⌋ = 6. Anda dapat menganggap ⌊log2 (n) ⌋ sebagai eksponen kekuatan tertinggi dua dalam representasi biner n.

  • +1 membawa eksponen ke kekuatan dua yang lebih tinggi berikutnya. Anda dapat menganggap langkah ini sebagai akuntansi untuk tempat 2 ^ 0 dari angka biner Anda, yang kemudian memberi Anda jumlah total bitnya. Sebagai contoh kita, itu 6 + 1 = 7. Anda mungkin tergoda untuk menggunakan fungsi plafon - ⌈x⌉, yang merupakan bilangan bulat terkecil yang lebih besar dari atau sama dengan x - untuk menghitung jumlah bit seperti itu:

bspec = ⌈log2 (n) ⌉

Namun, ini gagal ketika n adalah kekuatan dua.


Anda memiliki ruang ekstra di sana ...)+ 1)...-> ...)+1.... Juga, saya pikir Anda dapat mengembalikan nilai secara langsung daripada mencetaknya.
Loovjo

Anda dapat menurunkannya ke 31 dengan melakukan b=>1+(int)System.Math.Log(b,2); Konversi int menyediakan output yang sama dengan Math.Floor dan Anda tidak perlu pernyataan menggunakan jika Anda hanya mereferensikan Sistem sekali.
Grax32

6

C #, 32 byte

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

Mengubah parameter menjadi string biner dan mengembalikan panjang string.


4

Haskell, 20 byte

succ.floor.logBase 2

Menyusun fungsi yang mengambil basis logaritma 2, lantai, dan menambahkan 1.


4

Befunge-93 , 23 21 Bytes

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

Befunge adalah bahasa berbasis grid 2D (meskipun saya hanya menggunakan satu baris).

&                      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

Cobalah online!


@JamesHolderness Terima kasih, saya pikir itu bisa dipersingkat karena memiliki begitu banyak hash / spasi, tapi saya tidak bisa mengerti.
JayDepp





3

QBIC , 18 byte

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

Itu luar biasa Mike! Tetapi bagaimana cara kerjanya?

:        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

Untuk sekali, Java memiliki beberapa builtin berguna! Sekarang, kita hanya perlu beberapa nama pendek ...

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

Cobalah online!

Tentu saja, Anda dapat melakukan ini tanpa builtin ( lihat jawaban Snowman ), tetapi untuk jumlah byte yang lebih tinggi.


3

Oktaf, 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'))

Oktaf memiliki dua fungsi untuk mengubah angka desimal menjadi angka biner.

dec2binmengubah angka menjadi string karakter 1dan 0(nilai ASCII 48dan 49). Panjang string akan sama dengan jumlah bit yang diperlukan, kecuali ditentukan lain. Karena karakter 1dan 0non-nol, kita dapat menggunakan nnzuntuk menemukan jumlah elemen seperti ini: @(x)nnz(dec2bin(x)). Ini 19 byte, jadi ini terkait dengan jawaban Oktaf Luis Mendo lainnya .

Bisakah kita menggunakan lebih baik de2bi?

de2biadalah fungsi yang mengembalikan angka-angka biner sebagai vektor dengan angka-angka 1dan 0sebagai bilangan bulat, bukan karakter. de2bijelas dua byte lebih pendek dari dec2bin, tetapi kita tidak bisa lagi menggunakan nnz. Kita dapat menggunakan nnzjika kita menambahkan 1semua elemen, atau membuatnya menjadi vektor logis dengan truenilai saja . @(x)nnz(de2bi(x)+1)dan @(x)nnz(de2bi(x)<2)keduanya 19 byte. Menggunakan numeljuga akan memberi kita 19 byte @(x)numel(de2bi(x)),.

rowsadalah satu byte lebih pendek dari numel, tetapi de2bimengembalikan vektor horizontal, sehingga harus ditransposisi @(x)rows(de2bi(x)')kebetulan 19 byte juga.



2

Retina ,  44  23 byte

Membutuhkan terlalu banyak memori untuk dijalankan untuk nilai input yang besar. Mengonversi menjadi unary, lalu berulang kali membaginya dengan 2, menghitung berapa kali hingga mencapai nol. Hitungan byte mengasumsikan penyandian ISO 8859-1.

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

Cobalah online


1
Saya tidak yakin ini valid. Ini bukan kasus "itu membutuhkan lebih banyak memori daripada yang mungkin Anda miliki" tetapi "itu membutuhkan lebih banyak memori daripada yang bisa ditangani Retina sendiri". Secara khusus, konversi awal ke unary akan gagal untuk input pesanan 2 ^ 30 ke atas, karena keterbatasan dalam implementasi Retina.
Martin Ender

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.