Скільки бітів я вміщую


52

Для будь-якого позитивного 32-бітного цілого числа ( 1 ≤ n ≤ 0xFFFFFFFF) виведіть кількість бітів, необхідних для представлення цього цілого числа.

Тестові справи

| 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

Так f(16)би надрукувати чи повернути5

Це . Виграє найкоротший код у байтах


2
Це стеля логарифму основи-2.
orlp

23
@orlp Насправді цеfloor(log2(num))+1
Kritixi Lithos

2
@KritixiLithos Вправо.
orlp

3
Ніколи не пам'ятаю, щойно зрозумів, що розрізнення важливо, коли numє сила двох.
Брайан J

11
Це тривіальний виклик з великою кількістю банальних рішень. Однак є і деякі нетривіальні рішення. Виборцям: Будь ласка, прочитайте перше речення цього мета-повідомлення перед тим, як скасувати вбудовані функції. (смиренно взято з цього коментаря )
Kritixi Lithos

Відповіді:


30

16
Езотерична мова знову перемогла ...bg
devRicher

20
@devRicher Я очікую, що мене все-таки поб'є рішення в 1 байт, якщо чесно.
Чарівна урва восьминога

9
Принаймні, ця відповідь отримує результати; це не в bg.
NoOneIsHere

3
bgв ігрових засобах bad game:)
YoYoYonnY

1
@yoyoyonny або поле битви ха-ха.
Чарівний восьминога Урна

35

JavaScript (ES6), 18 байт

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>


Це одне з небагатьох нетривіальних рішень тут. Приємна тактика!
Kritixi Lithos

1
Чи має бути n>>>1підтримка n > 0x7FFFFFFF?
Арнольд

@Arnauld Хм, не знав, що >>не вдалося на nтакому високому рівні. Дякую.
ETHproductions

Приємно, моя перша спроба булаf=(a,b=1)=>a>1?f(a>>1,++b):b
Bassdrop Cumberwubwubwub

28

x86 Збірка, 4 байти

Припускаючи, що Констант в EBX:

bsr eax,ebx
inc eax

EAX містить кількість бітів, необхідних для Constant.

Байтів: ☼¢├@

Шістнадцятковий: ['0xf', '0xbd', '0xc3', '0x40']


2
Чи можете ви включити шістнадцятковий код фактично складеного 8-байтового коду збірки x86?
Loovjo

Зробив так. І дякую, бо зрозумів, що помилився. Я додав "inc eax", щоб відповідати правилам. Я втратив байт. :(
z0rberg

О, ух, ти змінив мій пост на правильне форматування. Дякуємо, що виправили це!
z0rberg

2
До речі, в поданнях Асамблеї можна припустити, що вхід вже зберігається в конкретному реєстрі , тому я думаю, що ви могли б відточити кілька байт таким чином.
Loovjo

1
Чи прийнято вважати подання складання числом байтів складеного машинного коду, а не вихідним кодом мови збірки?
smls

18

Він працює і в Python 2.
vaultah

1
Це дійсно так. Забутий Int Python 2 був шириною 64 біти, а не 32 бітом.
Денніс

Python 3's bit_lengthє bit_length().
dfernan

2
@dfernan Це не виклик функції; це функція. Якщо n - int , int.bit_length(n)і n.bit_length()зробіть точно так само.
Денніс

2
@dfernan int.bit_length(n)- це виклик функції , і таким чином фрагмент, який передбачає, що вхід зберігається у змінній. Це НЕ суперечить нашим правилам, тому додавання (n)зробить цей відповідь недійсним. Однак int.bit_lengthоцінює функцію і може бути збережений у змінній для подальшого використання. Це дозволено за замовчуванням.
Денніс

15

Лабіринт , 13 12 байт

 ?
_:
2/#(!@

Спробуйте в Інтернеті!

Пояснення

Програма просто неодноразово ділить вхід на 2, поки не дорівнює нулю. Кількість кроків відслідковується шляхом дублювання значення на кожному кроці. Після зменшення до нуля ми надрукуємо глибину стека (мінус 1).

Програма починається з того, ?що читає вхід. Основна петля - це блок 2x2 внизу, що йде проти годинникової стрілки:

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

Як тільки значення дорівнює нулю після повної ітерації, лінійний біт в кінці виконується:

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

5
Це рішення є повним - воно вимагає введення та надання відповіді, а не використовує жодної існуючої функції для цієї конкретної мети - він розраховує відповідь вручну. Для мене це більше відповідає духу гри, ніж більшість інших відповідей.
Йоган

15

C, 31 байт

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

... Тоді я подумав про рекурсію. Від незрозумілого до очевидного, і з однієї четвертості довжини скинуто.

Побачити його наживо на Коліру


C, 43 байти

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

Виклик fз непідписаним значенням (наприклад f(42u)) призведе до повернення його бітової довжини. Навіть працює на 0u!

Недолікований і пояснив: ( відхилення відкосів )

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

Побачити його наживо на Коліру


ОП гарантує n> = 1, тому n?...:0не потрібно.
Божевільний фізик

1
@MadPhysicist добре, що мені доведеться десь зупинити рекурсію, чи не так?)
Квентін

OIC. Не читав уважно, зараз відчуваю себе дурнем. Акуратний відповідь у будь-якому випадку.
Божевільний фізик

@MadPhysicist не хвилюйтесь, дуже дякую :)
Квентін

Для нерекурсивного рішення, що передбачає вирази виразів gcc, я вважаю, що ви могли бути схильні використовувати і цей #define f(n) ({64-__builtin_clzl(n);})підхід.
Мореакі


14

Perl 6 , 7 байт

*.msb+1

Спробуй це

Пояснення:

* перетворює його в лямбда WeverCode і вказує, куди слід ввести дані

.msb на Int повертає індекс найзначнішого біта (на основі 0)

+1поєднується в лямбду і додає один до можливого результату виклику .msb.


13

Макрос препроцесора (з розширеннями gcc), 26

#define f 32-__builtin_clz

Використовується вбудований нульовий лічильник GCC .

Назвіть це як функцію, наприклад f(100).

Спробуйте в Інтернеті .


О, уау, я думав про використання вбудованого, але відкинув ідею, бо думав, що це буде занадто довго ... Добре зіграно.
Квентін

Пощастило, що ОП вказано n> = 1: D
Матьє М.

12

Сітківка , 56 37 байт

Це рішення працює з усіма необхідними вхідними значеннями.

Найбільшою проблемою, з якою стикається Ретіна в цьому виклику, є той факт, що її рядки мають максимальну довжину 2 ^ 30 символів, тому звичайний спосіб поводження з числами (одинарне представлення) не працює зі значеннями, що перевищують 2 ^ 30.

Щоб вирішити цю проблему, я застосував інший підхід, зберігаючи своєрідне десяткове представлення чисел, але там, де кожна цифра написана одинаково (я називаю це представлення цифрова ). Наприклад, число 341було б записане, як 111#1111#1#у цифровій формі. За допомогою цього представлення ми тепер можемо працювати з числами до 2^30/10цифр (~ сто мільйонів цифр). Він менш практичний, ніж стандартний уніар для довільної арифметики, але, доклавши трохи зусиль, ми могли б робити будь-які операції.

ПРИМІТКА: в цифрових системах теоретично може використовуватися будь-яка інша база (наприклад, двійковий 110буде 1#1##в базі 2, оцифрований), але оскільки Retina має вбудовані для перетворення між десятковими та одинарними і немає прямого способу поводження з іншими базами, десятковий, мабуть, є найбільш керованою базою.

Алгоритм, який я використав, робить послідовні цілі ділення на два, поки ми не досягнемо нуля, кількість ділень, які ми зробили, - це кількість бітів, необхідних для представлення цього числа.

Отже, як ми ділимося на два в цифрових умовах? Ось фрагмент сітківки, який робить це:

(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

Цієї заміни достатньо, щоб ділити цифрове число на 2, нам просто потрібно видалити можливі .5s з кінця, якщо початкове число було непарним.

Отже, ось повний код, ми продовжуємо ділити на два, поки не залишиться цифр у цифрі, і ставимо буквальне nперед рядком при кожній ітерації: число nв кінці є результатом.

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

Спробуйте в Інтернеті!


Оновлене рішення, 37 байт

Великий рефакторинг з багатьма хорошими ідеями, які займають гольф приблизно на третину довжини, все завдяки Мартину Ендеру!

Основна ідея полягає у використанні _в якості нашого одинарного символу: таким чином ми можемо використовувати звичайні цифри в нашому рядку до тих пір, поки ми перетворюємо їх назад в _s, коли це потрібно: це дозволяє нам зберегти багато байт на поділі та на вставці декількох цифр.

Ось код:

<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

Спробуйте в Інтернеті!


1
Я використав аналогічну числову форму (але назвав її унарно-кодованою десятковою ), що досить зручно для арифметики з Sed.
Toby Speight


10

Джольф, 2 байти

lB

Просто перетворіть у двійкове і потім знайдіть довжину.



10

JavaScript ES6, 19 байт

a=>32-Math.clz32(a)

Math.clz32повертає кількість провідних нульових бітів у 32-бітному бінарному поданні числа. Отже, щоб отримати необхідну кількість бітів, все, що нам потрібно зробити, - це зменшити число з 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
Альтернатива a=>1+Math.log2(a)|0також - 19 байт.
Ніл

5
@Neil 1+...|0кричить мінус тильда ! a=>-~Math.log2(a)є 18
edc65

@ edc65 я рахую 17 ... але так, я був впевнений, що щось мені не вистачає, дякую, що вказав на це.
Ніл

@Neil Не соромтеся опублікувати це як окрему відповідь. Він використовує інший метод, ніж моя відповідь, тому було б несправедливо використовувати ваше для зменшення кількості байтів
Bassdrop Cumberwubwubwub

10

інструменти bash / Unix, 16 байт

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

Збережіть це у сценарії та передайте введення як аргумент. Кількість бітів, необхідних для представлення цього числа у двійковій формі, буде надруковано.

Ось пояснення:

DC - калькулятор на основі стека. Його вхід, розібраний на лексеми, полягає в:

2 - Натисніть 2 на стек.

o - Спустіть значення зі стека (що дорівнює 2) та зробіть його базовою для виводу (тому вихід тепер є двійковим).

Значення аргументу для програми bash ($ 1) - Натисніть на цей аргумент на стек.

n - Спустіть значення зі стека (що є вхідним номером) і надрукуйте його (у двійковому вигляді, оскільки це вихідна база) без відмітки нового рядка.

Отже команда dc друкує число у двійковій формі.

Вихід dc передається в команду wc з опцією -c, яка друкує кількість символів на своєму вході.

Кінцевим результатом є друк кількості цифр у двійковому поданні аргументу.


Хороший вибір мови, але було б ще крутіше, якби ви включили пояснення.
NH.

@NH Дякую Я додав пояснення.
Мітчелл Спектор

9

Google Таблиці, 15 байт

Здійснює введення з комірки A1та виводить у клітинку, яка містить формулу

=Len(Dec2Bin(A1

або

=Int(1+Log(A1,2

або

=Int(Log(2*A1,2

Excel, 17 байт

Те саме, що вище, але відформатовано для MS Excel

=Len(Dec2Bin(A1))

або

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

або

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


8

Желе, 2 байти

BL

Перетворюється на двійкове, знаходить довжину.


8

C #, 63 45 31 байт

Збережено 18 байт, завдяки Loovjo та TuukkaX

Збережено 14 байт, завдяки Grax

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

Він використовує, що десяткове число n має ⌊log2 (n) ⌋ + 1 біт, що описано на цій сторінці:

Кількість бітів у певному десятковому цілому числі

Позитивне ціле число n має біт, коли 2 ^ (b-1) ≤ n ≤ 2 ^ b - 1. Наприклад:

  • 29 має 5 біт, тому що 16 ≤ 29 ≤ 31, або 2 ^ 4 ≤ 29 ≤ 2 ^ 5 - 1
  • 123 має 7 біт, тому що 64 ≤ 123 ≤ 127, або 2 ^ 6 ≤ 123 ≤ 2 ^ 7 - 1
  • 967 має 10 біт, тому що 512 ≤ 967 ≤ 1023, або 2 ^ 9 ≤ 967 ≤ 2 ^ 10 - 1

Для більшої кількості ви можете ознайомитись з таблицею повноважень двох, щоб знайти послідовні повноваження, які містять ваше число.

Щоб зрозуміти, чому це працює, подумайте, наприклад, про двійкові представлення цілих чисел 2 ^ 4 до 2 ^ 5 - 1. Вони від 10000 до 11111, усі можливі 5-бітні значення.

Використання логарифмів

Вищеописаний спосіб можна констатувати і іншим способом: кількість бітів - це показник найменшої потужності на два, більший за ваше число. Ви можете це констатувати математично як:

bspec = ⌊log2 (n) ⌋ + 1

Ця формула складається з трьох частин:

  • log2 (n) означає логарифм в основі 2 з n, який є показником, до якого 2 піднято, щоб отримати n. Наприклад, log2 (123) ≈ 6.9425145. Наявність дробової частини означає, що n знаходиться між силами двох.

  • ⌊X⌋ - підлога x, яка є цілою частиною x. Наприклад, ⌊6.9425145⌋ = 6. Ви можете вважати ⌊log2 (n) ⌋ як показник найвищої сили двох у двійковому поданні n.

  • +1 приймає показника до наступної вищої сили двох. Ви можете вважати цей крок як облік 2 ^ 0-го місця вашого двійкового номера, яке потім дає вам загальну кількість біт. У нашому прикладі це 6 + 1 = 7. Ви можете спокуситись використовувати функцію стелі - ⌈x⌉, що є найменшим цілим числом, більшим або рівним x - для обчислення кількості бітів як такої:

bspec = ⌈log2 (n) ⌉

Однак це не вдається, коли n - потужність двох.


У вас є додатковий простір там ...)+ 1)...-> ...)+1.... Також я думаю, що ви можете повернути значення безпосередньо замість того, щоб надрукувати його.
Loovjo

Ви можете опустити його до 31, зробивши b=>1+(int)System.Math.Log(b,2); перетворення int, забезпечує такий же вихід, як Math.Floor, і вам не потрібно використовувати оператор, якщо ви посилаєтесь на System лише один раз.
Grax32

6

C #, 32 байти

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

Перетворює параметр у двійкову рядок і повертає довжину рядка.


4

Haskell, 20 байт

succ.floor.logBase 2

Складає функцію, яка займає логарифм основи 2, поверхи та додає 1.


4

Befunge-93 , 23 21 байт

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

Befunge - це 2D-сітка на основі мови (хоча я використовую лише один рядок).

&                      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

Спробуйте в Інтернеті!


@JamesHolderness Спасибі, я вважав, що це може бути скорочено, оскільки в ньому стільки хеш-просторів, але я не міг його повністю отримати.
JayDepp





3

QBIC , 18 байт

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

Це неймовірний Майк! Але як це працює?

:        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

Октава, 19 байт

@(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 має дві функції перетворення десяткових чисел у двійкові числа.

dec2binперетворює число в рядок символів 1і 0(ASCII-значення 48та 49). Довжина рядка буде дорівнює необхідній кількості бітів, якщо не вказано інше. Так як символи 1і 0відмінний від нуля, ми можемо використовувати , nnzщоб знайти число елементів , як це: @(x)nnz(dec2bin(x)). Це 19 байт, тому він пов'язаний з іншою відповіддю Октави Луїса Мендо .

Чи можемо ми краще використовувати de2bi?

de2biце функція, яка повертає двійкові числа як вектор з числами 1і 0як цілі числа, а не символи. de2biочевидно, на два байти коротше dec2bin, але ми більше не можемо використовувати nnz. Ми можемо використовувати, nnzякщо або додати 1до всіх елементів, або перетворити його в логічний вектор з лише trueзначеннями. @(x)nnz(de2bi(x)+1)і @(x)nnz(de2bi(x)<2)обидва є 19 байтами. Використання numelтакож дасть нам 19 байт @(x)numel(de2bi(x)).

rowsє на один байт коротше numel, але de2biповертає горизонтальний вектор, тому його потрібно перенести. @(x)rows(de2bi(x)')просто так трапляється і 19 байт.



2

Сітківка ,  44  23 байти

Для великих значень введення потрібна занадто велика кількість пам'яті. Перетворюється в одинарний, потім повторно ділиться на 2, рахуючи скільки разів, поки не досягне нуля. Кількість байтів передбачає кодування ISO 8859-1.

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

Спробуйте в Інтернеті


1
Я не впевнений, що це дійсно. Це не той випадок, «для цього потрібно більше пам’яті, ніж ви, мабуть, будете мати», але «для цього потрібно більше пам’яті, ніж сама Ретина може впоратися». Зокрема, початкове перетворення в одинарне не вдасться для входів порядку 2 ^ 30 і вище, через обмеження в реалізації Retina.
Мартін Ендер

Якщо він дійсний, його можна значно скоротити, хоча: tio.run/nexus/retina#@6@nxaWixaWdEKdhqK1paB9jyKViGM@l9/@/saUhAA
Мартін Ендер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.