Во сколько бит я вписываюсь


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это сила двух.
Брайан Джей

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
Хорошо

28

Сборка x86, 4 байта

Принимая константу в EBX:

bsr eax,ebx
inc eax

EAX содержит количество битов, необходимых для константы.

Б: ☼¢├@

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


2
Не могли бы вы включить hexdump фактического 8-байтового скомпилированного кода сборки x86?
Loovjo

Сделал так. И спасибо, потому что я понял, что сделал ошибку. Я добавил "inc eax", чтобы соответствовать правилам. Я потерял байт. :(
z0rberg's

Ух ты, ты изменил мой пост на правильное форматирование. Спасибо за исправление этого!
Z0rberg's

2
Кстати, в сборочных материалах можно предположить, что входные данные уже сохранены в определенном регистре , поэтому я думаю, что таким способом вы могли бы сократить несколько байтов.
Loovjo

1
Является ли общепринятым считать количество сборок как количество байтов скомпилированного машинного кода, а не как исходный код на языке ассемблера?
смс

18

Python , 14 байт

int.bit_length

Попробуйте онлайн!


Это работает и в Python 2.
vaultah

1
Это действительно так. Забыл, что int Python 2 был 64 бит, а не 32 бит.
Деннис

Python 3 - х bit_lengthесть bit_length().
Дфернан

2
@dfernan Это не вызов функции; это функция. Если n - это целое число , int.bit_length(n)и n.bit_length()делать то же самое.
Деннис

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

15

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

 ?
_:
2/#(!@

Попробуйте онлайн!

объяснение

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

Программа начинается с того, ?что читает ввод. Основной цикл - это блок 2х2 ниже, идущий против часовой стрелки:

:   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;}

... Тогда я подумал о рекурсии. От неясного к очевидному, и с одной четвертой длины отпадает.

Посмотрите это в прямом эфире на Coliru


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

Посмотрите это в прямом эфире на Coliru


ОП гарантирует n> = 1, поэтому n?...:0не является необходимым.
Безумный физик

1
@MadPhysicist ну, я должен где-то остановить рекурсию, не так ли;)
Квентин,

ОИС. Не читал внимательно, теперь чувствую себя тупицей. Аккуратный ответ в любом случае.
Безумный физик

@MadPhysicist не беспокойтесь, большое спасибо :)
Квентин

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


14

Perl 6 , 7 байт

*.msb+1

Попробуй

Объяснение:

* превращает его в лямбду-бы то ни было и указывает, куда поместить вход

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

+1объединяется в лямбду и добавляет единицу к конечному результату вызова .msb.


13

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

#define f 32-__builtin_clz

Использует встроенные в GCC счетчики ведущих нулей .

Вызовите это как функцию, например f(100).

Попробуйте онлайн .


Ух ты, я думал об использовании встроенного, но отказался от идеи, потому что думал, что это будет слишком долго ... Хорошо сыграно.
Квентин

К счастью, ОП указала n> = 1: D
Матье М.

12

Retina , 56 37 байт

Это решение работает со всеми необходимыми входными значениями.

Самая большая проблема, с которой Retina сталкивается в этой задаче, заключается в том, что ее строки имеют максимальную длину 2 ^ 30 символов, поэтому обычный способ работы с числами (унарное представление) не работает со значениями, превышающими 2 ^ 30.

Чтобы решить эту проблему, я принял другой подход, сохраняя своего рода десятичное представление чисел, но где каждая цифра пишется в унарном порядке (я назову это представление цифрой ). Например, число 341будет написано как 111#1111#1#в цифре. С этим представлением мы можем теперь работать с числами до 2^30/10цифр (~ сто миллионов цифр). Это менее практично, чем стандартное унарное для произвольной арифметики, но, приложив немного усилий, мы могли бы выполнять любые операции.

ПРИМЕЧАНИЕ: digitunary в теории может использовать любую другую базу (например, двоичная 110будет 1#1##в base 2 digitunary), но, поскольку Retina имеет встроенные функции для преобразования между десятичной и унарной и не имеет прямого способа иметь дело с другими базами, десятичная дробь, вероятно, является наиболее управляемой базой.

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

Итак, как мы можем разделить на два в цифре? Вот фрагмент 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, нам просто нужно удалить возможные .5 с конца, если исходное число было нечетным.

Итак, вот полный код, мы продолжаем делить на два до тех пор, пока в числе не останутся цифры, и ставим литерал 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
Я использовал аналогичную числовую форму (но назвал ее Unary-Coded Decimal ), которая довольно удобна для арифметики с Sed.
Тоби Спайт


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
@ Нил 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 Спасибо. Я добавил объяснение.
Митчелл Спектор

9

Google Sheets, 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

C #, 63 45 31 байт

Сохранено 18 байт, благодаря Loovjo и TuukkaX

Сохранено 14 байт, благодаря Grax

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

Он использует, что десятичное число n имеет ⌊log2 (n) ⌋ + 1 бит, что описано на этой странице:

Количество битов в определенном десятичном целом числе

Положительное целое число n имеет b битов, когда 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. Наличие дробной части означает, что между степенями два.

  • ⌊X⌋ - это пол x, который является целой частью x. Например, .96.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, и вам не нужен оператор using, если вы только один раз ссылаетесь на 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 - это двумерный сеточный язык (хотя я использую только одну строку).

&                      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

Java 8, 34 27 байт

На этот раз в Java есть несколько полезных встроенных функций! Теперь нам просто нужны короткие имена ...

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

Попробуйте онлайн!

Конечно, вы можете сделать это без встроенных функций ( см. Ответ Snowman ), но для большего количества байтов.


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

Retina ,  44  23 байта

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

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

Попробуйте онлайн


1
Я не уверен, что это действительно. Это не тот случай, когда «требуется больше памяти, чем у вас, вероятно, будет», но «это требует больше памяти, чем может выдержать сама Retina». В частности, первоначальное преобразование в унарный произойдет сбой для входов порядка 2 ^ 30 и выше, из-за ограничений в реализации Retina.
Мартин Эндер

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