Kaç bit sığdırıyorum


52

Herhangi bir pozitif 32-bit tamsayı ( 1 ≤ n ≤ 0xFFFFFFFF) için, o tamsayıyı göstermek için gereken bit sayısını verin.

Test durumları

| 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

Yani f(16)yazdırır ya da geri döner5

Bu . Bayt cinsinden en kısa kod kazanır


2
Bu, taban-2 logaritmasının tavanıdır.
orlp

23
@orlp Bu aslındafloor(log2(num))+1
Kritixi Lithos

2
@KritixiLithos Sağ.
orlp

3
Boş ver, az önce numiktidarın ne kadar önemli olduğunu fark ettim .
Brian J

11
Bu, birçok önemsiz çözümü olan önemsiz bir zorluktur. Bununla birlikte, önemsiz bazı çözümler de var. Seçmenler için: Lütfen yerleşik işlevlerini kaldırmadan önce bu meta gönderinin ilk cümlesini okuyun . (alçakgönüllülükle bu yorumdan alınmıştır )
Kritixi Lithos

Yanıtlar:



35

JavaScript (ES6), 18 bayt

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>


Bu, burada önemsiz olmayan birkaç çözümden biridir. Güzel taktik!
Kritixi Lithos

1
n>>>1Desteklemek n > 0x7FFFFFFFmi olmalı ?
Arnauld,

@Arnauld Hmm, o kadar yüksek >>başarısız nolduğunu bilmiyordu . Teşekkürler.
ETHproductions

Güzel, ilk denememf=(a,b=1)=>a>1?f(a>>1,++b):b
Bassdrop Cumberwubwubwub

28

x86 Meclisi, 4 bayt

Sabit olduğunu varsayarak EBX:

bsr eax,ebx
inc eax

EAX, Constant için gereken bit sayısını içerir.

Bayt: ☼¢├@

onaltılık: ['0xf', '0xbd', '0xc3', '0x40']


2
Lütfen gerçek 8 byte'lık derlenmiş x86 Assembly kodunun hexdump'ını ekleyebilir misiniz?
Loovjo

Öyle yaptım. Ve teşekkür ederim, çünkü bir hata yaptığımı farkettim. Kurallara uyması için bir "inc eax" ekledim. Bir bayt kaybettim. :(
z0rberg'in

Vay canına, benim gönderimi uygun biçimlendirme olarak değiştirdin. Düzeltdiğiniz için teşekkürler!
z0rberg

2
Bu arada, Meclis başvuruları girdilerin zaten belirli bir kayıt defterinde saklandığını varsayabilir , bu yüzden birkaç bayttan bu şekilde uzaklaşabileceğinizi düşünüyorum.
Loovjo

1
Derleme gönderilerini derleme dili kaynak kodu yerine derlenmiş makine kodunun bayt sayısı olarak saymak alışılmış mıdır?
18

18

Python , 14 bayt

int.bit_length

Çevrimiçi deneyin!


Python 2'de de çalışıyor.
Vaultah,

1
Gerçekten de öyle. Unutmayın Python 2'nin int'si 32 bit değil 64 bit genişlikte idi.
Dennis,

Python 3 en bit_lengtholduğunu bit_length().
dfernan

2
@ ddfernan Bu bir işlev çağrısı değildir; bu bir fonksiyon. Eğer n bir olan int , int.bit_length(n)ve n.bit_length()tam olarak aynı şeyi.
Dennis,

2
@dfernan int.bit_length(n)bir işlev çağrısıdır ve bu nedenle, girişin bir değişkende saklandığını varsayan bir pasajdır . Bu edilir değil bu yüzden ekleme, bizim kuralları tarafından izin verilen (n)bu yanıt geçersiz hale getirecektir. Ancak, int.bit_lengthbir işleve göre değerlendirilir ve daha sonra kullanılmak üzere bir değişkene kaydedilebilir. Buna varsayılan olarak izin verilir.
Dennis,

15

Labirent , 13 12 bayt

 ?
_:
2/#(!@

Çevrimiçi deneyin!

açıklama

Program, girişi sıfıra kadar basitçe art arda 2'ye böler. Adımların sayısı, her adımdaki değerin kopyalanmasıyla takip edilir. Bir kez sıfıra düştüğünde yığın derinliğini (eksi 1) yazdırırız.

Program ?, girişi okur. Ana döngü daha sonra aşağıdaki 2x2 bloktur, saat yönünün tersine gider:

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

Tam bir yinelemeden sonra değer sıfır olduğunda, sondaki doğrusal bit yürütülür:

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

5
Bu çözüm tamamlandı - girdi alıyor ve cevabı veriyor ve bu özel amaç için mevcut herhangi bir işlevi kullanmıyor - cevabı manuel olarak hesaplıyor. Bana göre bu, oyunun ruhunda diğer cevapların çoğundan daha fazla.
Johan

15

C, 31 bayt

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

... Sonra özyinelemeyi düşündüm. Müstehcenden apaçık ortaya ve uzunluğun dörtte biri düştü.

Coliru'da canlı görün


C, 43 bayt

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

İmzasız bir değerle (örneğin ) çağrı fyapmak bit uzunluğunu "döndürür". Hatta için çalışıyor !f(42u)0u

Ungolfed ve açıkladı: (ters eğik çizgi ihmal)

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

Coliru'da canlı görün


OP n> = 1'i garanti ediyor, bu yüzden n?...:0gerekli değil.
Mad Physicist

1
@MadPhysicist iyi bir yere özyineyi durdurmak zorundayım, değil mi;)
Quentin

İKÖ. Dikkatli okumadım, şimdi bir aptal gibi hissediyorum. Her iki şekilde de düzgün cevap.
Mad Physicist

@MadPhysicist endişelenmeyin, çok teşekkür ederim :)
Quentin

Gcc deyimi ifadelerini varsayan özyinelemeli olmayan çözüm için, #define f(n) ({64-__builtin_clzl(n);})yaklaşımı da kullanmaya meyilli olduğunuzu düşünüyorum .
Moreaki

14

Mathematica, 9 bayt

BitLength

Alternatif:

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



12

Retina , 56 37 bayt

Bu çözüm gerekli tüm giriş değerleriyle çalışır.

Retina'nın bu zorlukla karşılaştığı en büyük sorun, karakter dizilerinin maksimum 2 ^ 30 karakter uzunluğuna sahip olmasıdır, bu yüzden normal sayıların (unary temsili) 2 ile 30'dan büyük değerlerle çalışmaması gerekir.

Bu problemi çözmek için farklı bir yaklaşım benimsedim, sayıları bir miktar ondalık gösterimi koruyarak, ancak her bir basamağın aynı şekilde yazıldığı (bu temsili basamak olarak adlandıracağım ). Mesela bu rakam sayısal 341olarak yazılır 111#1111#1#. Bu gösterimle artık rakamlara kadar 2^30/10rakamlarla (~ yüz milyon rakam) çalışabiliriz . Keyfi aritmetik için standart unary'den daha az pratiktir, ancak biraz çaba sarf ederek her türlü işlemi yapabiliriz.

NOT: teoride digitunary (örn ikili başka tabanını kullanabilirsiniz 110olacağını 1#1##taban 2 digitunary), ancak Retina ondalık ve tekli ve diğer bazlar ile başa çıkmak için hiçbir doğrudan yol arasında dönüştürme yerleşiklerini beri, ondalık muhtemelen en yönetilebilir bir başlangıç noktasıdır.

Kullandığım algoritma, sıfıra ulaşana kadar iki kat ardışık tamsayı bölümleri yapmaktır, yaptığımız bölüm sayısı bu sayıyı temsil etmek için gereken bit sayısıdır.

Peki, sayısal olarak iki ile nasıl böleriz? İşte bunu yapan Retina pasajı:

(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

Bu değiştirme, bir sayısal sayıyı 2'ye bölmek için yeterlidir, orijinal sayı tuhafsa yalnızca 5.

Yani, tam kod burada, sayıda hala rakamlar gelinceye kadar ikiye bölünmeye devam ediyoruz nve her yinelemede dizenin önüne bir hazır bilgi veriyoruz : sonuçtaki nsonuç.

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

Çevrimiçi deneyin!


Güncelleştirilmiş çözüm, 37 bayt

Martin Ender sayesinde, uzunluğun yaklaşık üçte birini golf oynayan pek çok iyi fikirle büyük refactoring!

Ana fikir, _tek sembolümüz olarak kullanmaktır : bu şekilde dizgimizdeki normal rakamları tekrar kullanabildiğimiz sürece kullanabiliriz._ , gerektiğinde s'ye çevirdiğimiz sürece kullanabiliriz. basamak.

İşte kod:

<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

Çevrimiçi deneyin!


1
Sed ile aritmetik için oldukça kullanışlı olan benzer bir sayısal form kullandım (ancak Unary-Coded Decimal denir ).
Toby Speight

11

Ruby, 19 16 bayt

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

3 baytlık golf attığın için teşekkürler Jordan


Sen bir byte kaydedebilirsiniz %: ->n{("%b"%n).size}.
Ürdün

3
Bu kısadır Bekle: ->n{"%b"%n=~/$/}.
Ürdün

10

Jolf, 2 bayt

lB

Sadece ikiliye dönüştürmek ve uzunluğu bulmak.



10

JavaScript ES6, 19 bayt

a=>32-Math.clz32(a)

Math.clz32Bir sayının 32-bit ikili gösteriminde baştaki sıfır bitlerin sayısını döndürür. Böylece, gereken bit miktarını elde etmek için tek yapmamız gereken, bu sayıyı 32'den çıkarmaktır.

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
Alternatif a=>1+Math.log2(a)|0aynı zamanda 19 bayttır.
Neil

5
@Neil eksi tilde1+...|0 bağırıyor ! 18a=>-~Math.log2(a)
edc65

@ edc65 17'yi saydım ... ama evet, bir şeyi kaçırdığımdan emindim, belirttiğiniz için teşekkürler.
Neil

@Neil Ayrı bir cevap olarak göndermek için çekinmeyin.
Cevabımdan

10

bash / Unix araçları, 16 bayt

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

Bunu bir betiğe kaydedin ve girişi bir argüman olarak iletin. Bu sayıyı ikili olarak göstermek için gereken bit sayısı yazdırılır.

İşte bir açıklama:

dc, yığın tabanlı bir hesap makinesidir. Jetonlara ayrıştırılmış girişi:

2 - Yığına 2 basın.

o - Yığınından (2 olan) bir değer girin ve çıktı tabanını yapın (bu nedenle çıktı şimdi ikilidir).

Bash programındaki argümanın değeri ($ 1) - Bu argümanı yığına it.

n - Yığınından (giriş numarası olan) bir değer girin ve izleyen satırsonu olmadan yazdırın (ikili, çünkü bu taban taban).

Böylece dc komutu, sayıyı ikili olarak basar.

DC çıkışı, girişindeki karakter sayısını yazdıran -c seçeneğiyle wc komutuna bağlanır.

Sonuç, argümanın ikili gösterimindeki basamak sayısını yazdırmaktır.


Dil seçimi güzel, ancak bir açıklama eklerseniz daha iyi olurdu.
NH.

@ NH Teşekkürler. Bir açıklama ekledim.
Mitchell Spector

9

Google Sayfaları, 15 Bayt

Hücreden girdi alır A1ve formülü tutan hücreye çıktılar

=Len(Dec2Bin(A1

veya

=Int(1+Log(A1,2

veya

=Int(Log(2*A1,2

Excel, 17 Bayt

Yukarıdakiyle aynı, ancak MS Excel için biçimlendirilmiş

=Len(Dec2Bin(A1))

veya

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

veya

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

8

Pyth, 3 bayt

l.B

Test paketi burada mevcuttur.

açıklama

l.BQ    Q is implicitly appended
   Q    eval(input)
 .B     convert Q to binary string
l       len(.B(Q))

Alternatif olarak: hslveya .El, içindel kütük tabanı 2'yi hesaplayan ve hsveya .Etavanı hesaplayan.
RK.


8

C #, 63 45 31 bayt

Loovjo ve TuukkaX sayesinde 18 bayt kaydedildi

Grax sayesinde 14 bayt kaydedildi

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

Ondalık bir sayı olan n, islog2 (n) ⌋ + 1 bit değerine sahip olduğunu ve bunun üzerinde bu sayfada :

Belirli bir Ondalık Tamsayıda Bit Sayısı

2 ^ (b-1) ≤ n ≤ 2 ^ b - 1 olduğunda pozitif bir tamsayı n bit eder. Örneğin:

  • 29'un 5 biti var çünkü 16 ≤ 29 or 31 veya 2 ^ 4 ≤ 29 ≤ 2 ^ 5 - 1
  • 123'ün 7 biti var çünkü 64 ≤ 123 ≤ 127 veya 2 ^ 6 ≤ 123 ≤ 2 ^ 7 - 1
  • 967'de 10 bit var, çünkü 512 ≤ 967 ≤ 1023 veya 2 ^ 9 ≤ 967 ≤ 2 ^ 10 - 1

Daha büyük sayılar için, numaranızı içeren ardışık güçleri bulmak için iki kişilik bir güç tablosuna başvurabilirsiniz.

Bunun neden işe yaradığını görmek için, örneğin 2 ^ 4 - 2 ^ 5 - 1 arasındaki tamsayıların ikili gösterimlerini düşünün. Bunlar 10000 ile 11111 arasında, tüm olası 5 bitlik değerler.

Logaritma Kullanımı

Yukarıdaki yöntem başka bir yolla da ifade edilebilir: bit sayısı, numaranızınkinden iki en küçük gücün üssüdür. Bunu matematiksel olarak şöyle ifade edebilirsiniz:

bspec = ⌊log2 (n) ⌋ + 1

Bu formül üç bölümden oluşuyor:

  • log2 (n), n'nin 2'ye yükseltildiği üs olan n'nin 2 tabanındaki logaritma anlamına gelir. Örneğin, log2 (123) ≈ 6.9425145. Kesirli bir parçanın varlığı n'nin iki güç arasında olduğu anlamına gelir.

  • ⌊X⌋, x'in tamsayı kısmı olan x'in zeminidir. Örneğin, .96.9425145⌋ = 6. ⌊log2 (n) ⌋ 'nin n'nin ikili gösterimindeki en yüksek gücün üssü olduğunu düşünebilirsiniz.

  • +1 üssü bir sonraki iki yüksek güce götürür. Bu adımı, ikilik numaranızın 2. sırasının hesap numarası olarak düşünebilirsiniz, bu da size toplam bit sayısını verir. Örneğimize göre, bu 6 + 1 = 7'dir. Bit sayısını hesaplamak için x'e eşit veya daha büyük en küçük tam sayı olan ⌈x⌉ tavan işlevini kullanmak isteyebilirsiniz:

bspec = ⌈log2 (n) ⌉

Ancak, n ikilik bir güç olduğunda bu başarısız olur.


İçinde fazladan bir alan var ...)+ 1)...-> ...)+1.... Ayrıca, değeri yazdırmak yerine doğrudan geri verebileceğinizi düşünüyorum.
Loovjo

Yaparak b=>1+(int)System.Math.Log(b,2); int değerini 31'e düşürebilirsiniz . İnt dönüşümü Math.Floor ile aynı çıktıyı sağlar ve yalnızca bir kez sisteme başvuru yaparsanız use ifadesine ihtiyacınız yoktur.
Grax32

6

C #, 32 bayt

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

Parametreyi bir ikili dizeye dönüştürür ve dizenin uzunluğunu döndürür.


4

Haskell, 20 bayt

succ.floor.logBase 2

Logaritma taban 2, kat ve 1 ekleyen bir işlev oluşturur.


4

Befunge-93 , 23 21 Bayt

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

Befunge, 2B ızgara tabanlı bir dildir (yalnızca bir satır kullanıyorum).

&                      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

Çevrimiçi deneyin!


@JamesHolderness Teşekkürler, çok fazla karmaşa / alan olduğu için kısaltılabileceğini düşündüm, ama tam olarak bulamadım.
JayDepp





3

QBIC , 18 bayt

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

Bu inanılmaz Mike! Ama nasıl çalışır?

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

Bir kereliğine Java'nın bazı faydalı bileşenleri var! Şimdi, daha kısa isimlere ihtiyacımız var ...

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

Çevrimiçi deneyin!

Elbette, bunu yerleşik olmadan yapabilirsiniz (Snowman'ın cevabına bakınız ), fakat daha yüksek bayt sayısı için.


3

Octave, 19 bayt

@(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, ondalık sayıları ikili sayılara dönüştürmek için iki işleve sahiptir.

dec2binSayıyı karakter dizgisine 1ve 0(ASCII-değerleri 48ve 49) dönüştürür. İpin uzunluğu, aksi belirtilmedikçe, gerekli bit sayısına eşittir. Karakterleri yana 1ve 0sıfırdan farklıysa, kullanabileceğimiz nnzböyle elemanların sayısını bulmak için: @(x)nnz(dec2bin(x)). Bu 19 bayttır, bu yüzden Luis Mendo'nun diğer Octave cevabıyla bağlantılı .

Kullanarak daha iyisini yapabilir miyiz de2bi?

de2biİkili sayıları, karakterlerle değil , sayılarla bir vektör olarak 1ve 0tam sayı olarak döndüren bir işlevdir . de2biAçıkçası iki bayttan daha kısa dec2bin, ancak artık kullanamayız nnz. Biz yapabilirsiniz kullanmak nnzbiz ya eklerseniz 1tüm elemanlarına veya yalnızca bir mantıksal vektör haline yapar truedeğerler. @(x)nnz(de2bi(x)+1)ve @(x)nnz(de2bi(x)<2)ikisi de 19 bayttır. Kullanımı numelda bize 19 bayt verecek @(x)numel(de2bi(x)).

rowsondan daha kısa olan bir bayttır numel, ancak de2biyatay bir vektör döndürür, bu nedenle aktarılmalıdır. @(x)rows(de2bi(x)')Sadece bu yüzden de 19 bayt olur.



2

Retina ,  44  23 bayt

Büyük giriş değerleri için çalıştırmak için çok fazla bellek gerektirir. Birliğe dönüştürür, ardından tekrar tekrar 2'ye bölerek sıfıra kadar kaç kez sayar. Bayt sayısı, ISO 8859-1 kodlamasını varsayar.

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

Çevrimiçi deneyin


1
Bunun geçerli olduğundan emin değilim. Bu, "muhtemelen sahip olacağınızdan daha fazla bellek gerektirir" durumu değil, "Retina'nın elinden daha fazla bellek gerektiriyor" durumu değil. Özellikle, birliğin ilk dönüşümü, Retina'nın uygulanmasındaki kısıtlamalar nedeniyle, 2 ^ 30 ve daha yukarı sıradaki girdiler için başarısız olacaktır.
Martin Ender

Eğer geçerliyse, yine de çok kısaltılabilir: tio.run/nexus/retina#@6@nxaWixaWdEKdhqK1paB9jyKViGM@l9/@/saUhAA
Martin Ender
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.