Середні біти: середній виклик


30

З огляду на ціле число N> = 1, виведіть середнє число біт у цілому цілому від 0 до N - 1

Специфікація

  • Вихід може бути обчислений як сума кількості бітів у двійковому поданні кожного цілого числа від 0 до N-1, поділена на N.
  • Бінарне подання цілого числа не має провідних нулів у цьому контексті, за винятком нуля, який у двійковій формі представлений як 0.
  • Вихід повинен бути точним як мінімум до 7 значущих цифр.

Приклад

N = 6

0: 0   : 1 bit
1: 1   : 1 bit
2: 10  : 2 bits
3: 11  : 2 bits
4: 100 : 3 bits
5: 101 : 3 bits

Середня кількість бітів = (1 + 1 + 2 + 2 + 3 + 3) / 6 = 2

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

Вхід => вихід

1 => 1
2 => 1
3 => 1.3333333
4 => 1.5
5 => 1.8
6 => 2
7 => 2.1428571

Знімок дошки

( звідси )

Зауважте, що сума (перш ніж ділити для знаходження середнього) є послідовністю на OEIS .


6
Гарне ім’я, дуже каламутне .
Rɪᴋᴇʀ

3
Для тих, хто не знає, я швидше схвалюю рішення з поясненням
трихоплакс

4
Не вистачає каламбурів, вам потрібно трохи більше, щоб це було ідеально.
клісмік

1
Я припускаю, що під "кожним числом" ви маєте на увазі "кожне ціле число "?
Cyoce

@Cyoce так, дякую, що вказав на це - я редагував, щоб уточнити.
трихоплакс

Відповіді:



9

Jelly, 6 bytes

R’BFL÷

Try it online!

R’BFL÷  Main monadic chain. Argument: n

R       yield [1, 2, ..., n]
 ’      decrement; yield [0, 1, ..., n-1]
  B     convert to binary; yield [[0], [1], [1,0], [1,1], ...]
   F    flatten list; yield [0, 1, 1, 0, 1, 1, ...]
    L   length of list
     ÷  divide [by n]

7

Octave, 29 bytes

@(n)1+sum(fix(log2(1:n-1)))/n

Explanation

              log2(1:n-1)       % log2 of numbers in range [1..n-1]
                                % why no 0? because log2(0) = -Inf  :/
          fix(           )      % floor (more or less, for positive numbers)
      sum(                )     % sum... wait, didn't we miss a +1 somewhere?
                                % and what about that missing 0?
                           /n   % divide by n for the mean
    1+                          % and add (1/n) for each of the n bit lengths 
                                % (including 0!)

Зразок запущений на ideone.


6

Python 3, 43 байти

def f(n):x=len(bin(n))-2;return(2-2**x)/n+x

Використовує формулу на сторінці OEIS . Дивно, але названа функція тут якось дешевша через призначення x.

Альтернативний підхід для 46 байт:

lambda n:-~sum(map(int.bit_length,range(n)))/n

На жаль, -~необхідне з тих пір (0).bit_length()є 0, але навіть тоді це було б занадто довго.


6

Джулія, 27 байт

n->endof(prod(bin,0:n-1))/n

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

Як це працює

Since * is string concatenation in Julia, prod can be used to concatenate an array of strings. It optionally takes a function as first argument that it maps over the second one before taking the actual "product", so prod(bin,0:n-1) is the string of the binary representation of all integers in the desired range. Taking the length with endof and dividing by n yields the mean.


5

Julia, 28 bytes

n->mean(ceil(log2([2;2:n])))

Since bin doesn't automatically map over arrays, we're using ceil(log2(n)) to get the number of bits in n-1. This works out nicely because Julia's a:b notation is inclusive on both ends, so 2:n is a range from 2 to n, but we're really calculating the number of bits for numbers in the range 1:n-1. Unfortunately though, we need to tack on an extra 2 to account for 0.

Try it online!


5

MATL, 9 байт

q:ZlksG/Q

Try it Online!

Modified version with all test cases

Пояснення

    % Implicitly grab input (N)
q:  % Create array from 1:N-1
Zl  % Compute log2 for each element of the array
k   % Round down to the nearest integer
s   % Sum all values in the array
G   % Explicitly grab input again
/   % Divide by the input
Q   % Add 1 to account for 0 in [0, ... N - 1]
    % Implicitly display the result

Оснастка !! (наповнювач)
Девід

@David Насправді, твій був правильний. Копіювання введення на початку не працює для інших значень ... вам потрібно G/Qв кінці.
стакан

5

MATL, 9 байт

:qBYszQG/

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

Пояснення

:qBYszQG/
:               % take vector [1..n]
 q              % decrement by 1 to get [0..n-1]
  B             % convert from decimal to binary
   Ys           % cumulative sum (fills in 0's after first 1)
     z          % number of nonzero elements
      Q         % increment by 1 to account for zero
       G        % paste original input (n)
        /       % divide for the mean

5

Желе, 8 байт

Не коротший, але цікавий алгоритм і моє перше подання про Jelly:

Rl2Ċ»1S÷

R         1 to n
 l2       log2
   Ċ      ceiling
    »1    max of 1 and...
      S   sum
       ÷  divided by n

4

Желе, 10 байт

BL©2*2_÷+®

З пропозиції Sp3000.

Спробуйте тут.

Желе, 11 байт

æḟ2’Ḥ÷_BL$N

Не дуже короткий, але мені потрібні поради.

Спробуйте тут.

Використовуючи ту саму формулу, що і у відповіді Sp3000 . (Це не дуже важко здобути самостійно, диференціюючи геометричну прогресію.)


Подивіться на мою відповідь Джелі для довідки.
Лина монашка

@LeakyNun Він використовує інший підхід, і я не думаю, що він коли-небудь буде коротшим, ніж у вас. Але _BL$Nздавалося досить довгим ...
jimmy23013

Отже, у вашому коді "підлога до найближчої потужності 2, мінус 1, подвійний, ділення за входом, мінус двійкова довжина введення, від'ємна"?
Лина монашка

@LeakyNun Так ..
jimmy23013

3
Тільки незначно краще:BL©2*2_÷+®
Sp3000

4

Java, 135 95 90 байт

float a(int n){int i=0,t=0;for(;i<n;)t+=Integer.toString(i++,2).length();return t/(n+0f);}

Я думаю, ви можете позбутися інтерфейсу і просто створити функцію або лямбда. Також ви можете повернути значення замість того, щоб роздрукувати його в stdout
Frozn

Гаразд, я знову застосую ці правила.
Shaun Wild

Я думаю, що це слід дозволити. Оскільки в ОП нічого не вказано, я думаю, що застосовуються стандартні правила вводу / виводу .
Frozn

Так, функція прекрасна - вам не потрібна повна програма. Зауважте, що таблиця лідерів набирає рахунок у першому рядку, тому ваш рахунок наразі показує 135 замість 95.
трихоплакс

@trichoplax Ще останнє місце. Я звинувачую Яву особисто ...
Shaun Wild

3

Пітон 3, 46 байт

lambda x:sum(len(bin(i))-2for i in range(x))/x

Називай це так

f = lambda x: sum(len(bin(i))-2for i in range(x))/x
print(f(6))
# 2.0

Мені довелося повернути версію карти, тому що вона не вдалася для введення 5


3

05AB1E, 9 7 байт

Код:

L<bJg¹/

Пояснення:

L<         # range from 0..input-1
  b        # convert numbers to binary
   J       # join list of binary numbers into a string
    g      # get length of string (number of bits)
     ¹/    # divide by input

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

Редагувати: збережено 2 байти завдяки @Adnan


@Adnan: Дякую! Забув про Дж.
Емінья

3

C #, 87 байт

double f(int n){return Enumerable.Range(0,n).Average(i=>Convert.ToString(i,2).Length);}

Я написав відповідь C #, тому що не бачив її. Це моє перше повідомлення до одного з таких, тому, будь ласка, дайте мені знати, чи я роблю щось не так.


Ласкаво просимо до головоломки програмування та коду для гольфу Це чудова перша відповідь, +1. Ви можете змінити, doubleщоб floatзберегти один байт, або вам потрібна точність?
wizzwizz4

2
@ wizzwizz4 Дякую! У мене була така ж думка, але Середня () повертає дубль. Якщо я міняю свій тип повернення на плаваючий, я повинен явно видати подвійний і набрати 7 байт на цьому.
рейв

2

JavaScript (ES7), 38 32 байти

n=>(l=-~Math.log2(n))-(2**l-2)/n

Використання формули @ sp3000 (попередня версія була рекурсивним рішенням). Версія ES6 на 34 байти:

n=>(l=-~Math.log2(n))-((1<<l)-2)/n

Пояснення формули: Розглянемо випадок N = 55. Якщо ми запишемо двійкові числа (вертикально для економії місця), отримаємо:

                                11111111111111111111111
                111111111111111100000000000000001111111
        11111111000000001111111100000000111111110000000
    111100001111000011110000111100001111000011110000111
  11001100110011001100110011001100110011001100110011001
0101010101010101010101010101010101010101010101010101010

Розмір цього прямокутника дорівнює nl, тому середнє значення становить лише l, але нам потрібно виключити заготовки. Кожен ряд заготовок удвічі довший попереднього, тому загальна сума 2 + 4 + 8 + 16 + 32 = 64 - 2 = 2 л - 2.


2

J, 21 17 15 байт

Від 17 байт до 15 байт завдяки @Dennis.

+/@:%~#@#:"0@i.

Хто-небудь може мені допомогти в цьому гольф? ...

Безгольова версія

range        =: i.
length       =: #
binary       =: #:
sum          =: +/
divide       =: %
itself       =: ~
of           =: @
ofall        =: @:
binarylength =: length of binary "0
average      =: sum ofall divide itself
f            =: average binarylength of range

Я спробував альтернативний підхід, по stringifying списку двозначних цифр, що і вийшов з 25 байтами: %~>:@#@([:":10#.[:#:i.)-]. Ваше рішення виглядає досить оптимально.
Conor O'Brien

2

Perl 6 ,  34  32 байти

{$_ R/[+] map *.base(2).chars,^$_}

{$_ R/[+] map {(.msb||0)+1},^$_}

Пояснення:

{ 
  $_  # the input
  R/  # divides ( 「$a R/ $b」 is the same as 「$b / $a」 )
  [+] # the sum of:
  map
    {
      (
       .msb # the most significant digit (0 based)
       || 0 # which returns Nil for 「0.msb」 so use 0 instead
            # should be 「(.msb//0)」 but the highlighting gets it wrong
            # it still works because it has the same end result 
      ) 
      + 1   # make it 1 based
    },
    ^$_ # 「0 ..^ $_」 all the numbers up to the input, excluding the input
}

Тест:

use v6.c;

# give it a name
my &mean-bits = {$_ R/[+] map {(.msb||0)+1},^$_}

for 1..7 {
  say .&mean-bits
}

say '';

say mean-bits(7).perl;
say mean-bits(7).base-repeating(10);
1
1
1.333333
1.5
1.8
2
2.142857

<15/7>
(2. 142857)

2

Діалог APL , 14 байт

(+/1⌈(⌈2⍟⍳))÷⊢

range ← ⍳
log   ← ⍟
log2  ← 2 log range
ceil  ← ⌈
bits  ← ceil log2
max   ← ⌈
fix0  ← 1 max bits
sum   ← +/
total ← sum fix0
self  ← ⊢
div   ← ÷
mean  ← sum div self

2

Clojure, 71 64 63 байт

Схоже, співвідношення є нормальними відповідно до того, Який формат чисел прийнятний у виході?

(fn[n](/(inc(apply +(map #(.bitLength(bigint %))(range n))))n))

  • n = 1 => 1
  • n = 7 => 15/7

unolfolf (і трохи переписаний для зручності пояснення)

(fn [n]
 (->
  (->>
   (range n)                      ;;Get numbers from 0 to N
   (map #(.bitLength (bigint %))) ;;Cast numbers to BigInt so bitLength can be used
   (apply +)                      ;;Sum the results of the mapping
   (inc))                         ;;Increment by 1 since bitLength of 0 is 0
  (/ n)))                         ;;Divide the sum by N

стара відповідь, що використовується (float):

(fn[n](float(/(inc(apply +(map #(..(bigint %)bitLength)(range n))))n)))

вихід такий:

  • n = 1 => 1,0
  • n = 7 => 2,142857

Питання про прийнятність дробів або співвідношень раніше не виникало. Для цього виклику я прийму будь-який консенсус щодо того, яким повинен бути дефолт .
трихоплакс

1

Мінколанг 0,15 , 23 байти

n$z1z[i1+2l$M$Y+]kz$:N.

Спробуйте тут!

Пояснення

n$z                       Take number from input and store it in register (n)
   1                      Push 1 onto the stack
    z[                    For loop that repeats n times
      i1+                 Loop counter + 1
         2l$M             log_2
             $Y           Ceiling
               +          Add top two elements of stack
                ]         Close for loop
                 z$:      Float divide by n
                    N.    Output as number and stop.

Досить прямолінійна реалізація.


1

JavaScript ES5, 55 байт

n=>eval(`for(o=0,p=n;n--;o+=n.toString(2).length/p);o`)

Пояснення

n =>   // anonymous function w/ arg `n`
  for( // loop
      o=0,  // initalize bit counter to zero
      p=n   // copy the input
    ;n-- // will decrease input every iteration, will decrease until it's zero
    ;o+=    // add to the bitcounter
        n.toString(2)  // the binary representation of the current itearations's
                     .length // length
        /p   // divided by input copy (to avergage)
   );o       // return o variable  

1

Хун , 71 байт

|=
r/@
(^div (sun (roll (turn (gulf 0 (dec r)) xeb) add)) (sun r)):.^rq

... Я майже впевнений, що це насправді перший раз, коли я використав сердечники з плаваючою точкою Хуна. Це фактично реалізація, написана в Hoon, що витікає з SoftFloat, оскільки єдиними типами даних у Hoon є атоми та комірки.

Створіть функцію , яка приймає атом r. Створіть список із [0 .. (r - 1)], складіть карту зі списком, приймаючи двійковий логарифм числа, а потім складіть цей список за допомогою ++add. Перетворіть як вихідну складку, так і rв @rq(квадратичні числа з плаваючою точкою) за допомогою++sun:rq , а потім розділіть один на інший.

Найдивніша річ у цьому фрагменті - :.^rqкінець. a:bв Хуні означає "оцінювати а в контексті b". ++rqце серцевина, яка містить всю реалізацію в квадратичній точності, як бібліотека. Тож біг (sun 5):rq- це те саме, що робити(sun:rq 5) .

На щастя, сердечники в Хуні схожі на лялькових гнізд; коли ви оцінюєте руку, ++rqщоб отримати серцевину, вона також додає до неї весь stdlib, тож ви зможете продовжувати кататись, повертати і заливати, і все це весело, а не застрявати лише руками, визначеними в ++rq. На жаль, rq переосмислює ++addдодавання замість цього з плаваючою комою разом із тим, що він не має rв його контексті. .(весь сучасний контекст), однак.

Оцінюючи вираз у контексті, компілятор спочатку шукає глибину кінцівки. У нашому випадку a:[. rq]це виглядатиме в усьому поточному контекстіa перш ніж переходити до пошукуrq . Так addбуде шукати функцію, яка працює на атоми замість чисел з плаваючою комою ... але так буде div. У Hoon також є функція, коли використання ^nameбуде ігнорувати першу знайдену посилання, а шукати другу.

Звідти це просто за допомогою синтатичного цукру a^bрівності, щоб [a b]оцінити наш фрагмент як з нашим поточним контекстом, так і з квадроточною бібліотекою поплавця, ігноруючи атомний поділ на користь ++div:rq.

> %.  7
  |=
  r/@
  (^div (sun (roll (turn (gulf 0 (dec r)) xeb) add)) (sun r)):.^rq
.~~~2.1428571428571428571428571428571428

1

Насправді 7 байт:

;r♂├Σl/

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

Пояснення:

;r♂├Σl/
;        duplicate input
 r       push range(0, n) ([0, n-1])
  ♂├     map binary representation
    Σ    sum (concatenate strings)
     l/  divide length of string (total # of bits) by n

Якби не помилка, яку я щойно виявив, це рішення працювало б на 6 байт:

r♂├♂læ

æ - це вбудована середня команда.


Це не 10 байт? Я перевірив на сайті bytesizematters.com.
m654

1
@ m654 Фактично не використовує UTF-8, він використовує CP437 (або щось подібне).
Олексій А.

@AlexA. О, не знав цього.
m654

1
@ m654 Bytesizematters використовує повністю складене кодування, яке не існує (і не може ) існувати на практиці. Для UTF-8 використовуйте mothereff.in/byte-counter .
Денніс

@ Денніс Дякую за інформацію, я пам’ятаю про це.
m654


1

PowerShell v2 +, 64 байти

param($n)0..($n-1)|%{$o+=[convert]::ToString($_,2).Length};$o/$n

Дуже відверта реалізація специфікації. Петлі від 0до $n-1до |%{...}. Кожну ітерацію ми [convert]вводимо номер введення $_в базу рядків 2і беремо їїlength . Ми накопичуємо це в $o. Після закінчення петель просто ділимо$o/$n , залишаючи це на конвеєрі, і вихід неявний.

Поки це фактично коротше, ніж формула, яку використовують Sp та інші, оскільки [math]::Ceiling() як і [math]::Log()до смішного багатослівним. Базова конверсія в PowerShell є щасливою.



1

CJam, 13 12 11 байт

Один байт збережено завдяки @ Sp3000, а інший завдяки @ jimmy23013

rd_,2fbs,\/

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

Пояснення

Прямо. Застосовує визначення.

rd      e# read input and convert to double 
_       e# duplicate 
,       e# range from 0 to input minus 1
2fb     e# convert each element of the array to binary 
s       e# convert to string. This flattens the array
,       e# length of array 
\       e# swap 
/       e# divide 


1

Свіфт, 72 байти

func f(n:Double)->Double{return n<1 ?1:f(n-1)+1+floor(log2(n))}
f(N-1)/N

2
Вам не потрібно викликати функцію, залишаючи її як визначену функцію в порядку. Гарний перший пост.
Rɪᴋᴇʀ

1

J, 15 байт

%~[:+/#@#:"0@i.

Це монадійне дієслово, яке вживається так:

   f =: %~[:+/#@#:"0@i.
   f 7
2.14286

Спробуйте тут!

Пояснення

Я реалізував специфікацію виклику досить буквально. Є й інші підходи, але все виявилося довше.

%~[:+/#@#:"0@i.  Input is y
             i.  Range from 0 to y-1.
          "0@    For each number in this range:
      #@           Compute the length of
        #:         its base-2 representation.
  [:+/           Take the sum of the lengths, and
%~               divide by y.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.