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

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

Это . Самый короткий код в байтах выигрывает

Bassdrop Cumberwubwubwub
источник
2
Это потолок логарифма базы-2.
orlp
23
@orlp Это на самом делеfloor(log2(num))+1
Kritixi Lithos
2
@ KritixiLithos Правильно.
orlp
3
Неважно, только что понял, что отличное важно, когда numэто сила двух.
Брайан Джей
11
Это тривиальная задача с множеством тривиальных решений. Однако есть и некоторые нетривиальные решения. Избирателям: Пожалуйста, прочитайте первое предложение этого мета-поста перед тем, как отказаться от встроенных функций. (смиренно взято из этого комментария )
Kritixi Lithos

Ответы:

30

05AB1E , 2 байта

bg

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

Урна волшебного осьминога
источник
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>

ETHproductions
источник
Это одно из немногих нетривиальных решений здесь. Хорошая тактика!
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']

z0rberg-х
источник
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

Quentin
источник
ОП гарантирует n> = 1, поэтому n?...:0не является необходимым.
Безумный физик
1
@MadPhysicist ну, я должен где-то остановить рекурсию, не так ли;)
Квентин,
ОИС. Не читал внимательно, теперь чувствую себя тупицей. Аккуратный ответ в любом случае.
Безумный физик
@MadPhysicist не беспокойтесь, большое спасибо :)
Квентин
Для нерекурсивного решения, предполагающего выражения операторов gcc, я считаю, что вы, возможно, были склонны также использовать этот #define f(n) ({64-__builtin_clzl(n);})подход.
Мореаки
14

Mathematica, 9 байт

BitLength

В качестве альтернативы:

Floor@Log2@#+1&
#~IntegerLength~2&
Мартин Эндер
источник
14

Perl 6 , 7 байт

*.msb+1

Попробуй

Объяснение:

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

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

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

Брэд Гилберт b2gills
источник
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.
Тоби Спайт
11

Рубин, 19 16 байт

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

Спасибо Джордан за игру в гольф 3 байта

Алексис Андерсен
источник
Вы можете сохранить байты с %: ->n{("%b"%n).size}.
Джордан,
3
Подождите, это короче ->n{"%b"%n=~/$/}.
Джордан
10

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

lB

Просто преобразуйте в двоичный файл, а затем найдите длину.

Rɪᴋᴇʀ
источник
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>

Bassdrop Cumberwubwubwub
источник
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

Pyth, 3 байта

l.B

Тестовый набор доступен здесь.

объяснение

l.BQ    Q is implicitly appended
   Q    eval(input)
 .B     convert Q to binary string
l       len(.B(Q))
Майк Буфардечи
источник
В качестве альтернативы: hslили .El, в котором lвычисляется лог-база 2, и / hsили .Eвычисляется потолок.
РК.
8

Желе, 2 байта

BL

Преобразует в двоичный файл, находит длину.

Rɪᴋᴇʀ
источник
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;

Преобразует параметр в двоичную строку и возвращает длину строки.

Yytsi
источник
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

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

JayDepp
источник
@JamesHolderness Спасибо, я подумал, что его можно сократить, поскольку в нем так много хеша / пробелов, но я не мог его получить.
JayDepp
17 байтов
Джо Кинг,
3

CJam , 5 байтов

ri2b,

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

Прочитать input ( r), преобразовать в integer ( i), получить двоичное представление ( 2b), получить length ( ,).

Мартин Эндер
источник
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]
steenbergh
источник
3

Java 8, 34 27 байт

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

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

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

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

FlipTack
источник
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_
.

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

mbomb007
источник
1
Я не уверен, что это действительно. Это не тот случай, когда «требуется больше памяти, чем у вас, вероятно, будет», но «это требует больше памяти, чем может выдержать сама Retina». В частности, первоначальное преобразование в унарный произойдет сбой для входов порядка 2 ^ 30 и выше, из-за ограничений в реализации Retina.
Мартин Эндер
Если он действителен, его можно было бы значительно сократить: tio.run/nexus/retina#@6@nxaWixaWdEKdhqK1paB9jyKViGM@l9/@/saUhAA
Мартин Эндер,