Bits medios: un desafío promedio


30

Dado un entero N> = 1, genera el número medio de bits en un entero de 0 a N - 1

Especificación

  • La salida se puede calcular como la suma del número de bits en la representación binaria de cada entero de 0 a N-1, dividido por N.
  • La representación binaria de un entero no tiene ceros a la izquierda en este contexto, con la excepción de cero, que se representa como 0 en binario.
  • La salida debe ser precisa al menos a 7 cifras significativas.

Ejemplo

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

Número medio de bits = (1 + 1 + 2 + 2 + 3 + 3) / 6 = 2

Casos de prueba

Entrada => salida

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

Fragmento de la tabla de posiciones

(desde aquí )

Tenga en cuenta que la suma (antes de dividir para encontrar la media) es una secuencia en OEIS .


66
Bonito nombre, muy punny .
Rɪᴋᴇʀ

3
Para cualquiera que no sepa, es más probable que vote a favor de las soluciones con una explicación
trichoplax

44
No hay suficientes juegos de palabras, necesitas un poco más para que esto sea perfecto.
clismique

1
¿Asumo que por "cada número" quieres decir "cada número entero "?
Cyoce

@Cyoce sí, gracias por señalarlo, lo he editado para aclararlo.
Trichoplax

Respuestas:


13

Pyth, 6 bytes

.Oml.B

Pruébelo en línea aquí .

.Oml.BdUQ              Filling in implict vars

.O                     Average of list
 m   UQ                Map over [0..input)
  l                    Length of
   .B                  Binary string representation of int
    d                  Lambda var

En primer lugar, pero no apareciste en la tabla de clasificación: hice una pequeña edición en el encabezado para solucionarlo.
Trichoplax

9

Jalea, 6 bytes

R’BFL÷

Pruébalo en línea!

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

Octava, 29 bytes

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

Explicación

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

Ejecución de muestra en ideone .


6

Python 3, 43 bytes

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

Hace uso de la fórmula en la página OEIS . Sorprendentemente, una función con nombre es de alguna manera más barata aquí debido a la asignación a x.

Enfoque alternativo para 46 bytes:

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

Desafortunadamente, -~es necesario ya que (0).bit_length()es 0, pero incluso entonces sería un byte demasiado largo.


6

Julia, 27 bytes

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

Pruébalo en línea!

Cómo funciona

Como *es la concatenación de cadenas en Julia, prodse puede usar para concatenar una matriz de cadenas. Opcionalmente, toma una función como primer argumento que asigna sobre el segundo antes de tomar el "producto" real, por lo que prod(bin,0:n-1)es la cadena de la representación binaria de todos los enteros en el rango deseado. Tomar la longitud con endofy dividir entre n produce la media.


5

Julia, 28 bytes

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

Como binno se asigna automáticamente a las matrices, estamos usando ceil(log2(n))para obtener el número de bits n-1. Esto funciona bien porque la a:bnotación de Julia es inclusiva en ambos extremos, por lo que 2:nes un rango de 2 a n, pero realmente estamos calculando el número de bits para los números en el rango 1:n-1. Sin embargo, desafortunadamente, necesitamos agregar un extra 2para dar cuenta de 0.

Pruébalo en línea!


5

MATL, 9 bytes

q:ZlksG/Q

Pruébalo en línea!

Versión modificada con todos los casos de prueba.

Explicación

    % 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

¡¡Chasquido!! (relleno)
David

@David En realidad, el tuyo era correcto. Duplicar la entrada al principio no funciona para otros valores ... necesita G/Qal final.
vaso de precipitados

5

MATL, 9 bytes

:qBYszQG/

Pruébalo en línea!

Explicación

: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

Jalea, 8 bytes

No es un algoritmo más corto, pero interesante, y mi primer envío de Jelly:

Rl2Ċ»1S÷

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

4

Jalea, 10 bytes

BL©2*2_÷+®

De la sugerencia de Sp3000.

Pruébalo aquí.

Jalea, 11 bytes

æḟ2’Ḥ÷_BL$N

No muy corto pero necesito algunos consejos.

Pruébalo aquí.

Usando la misma fórmula que en la respuesta de Sp3000 . (No es muy difícil obtenerlo usted mismo, diferenciando la progresión geométrica).


Mira mi respuesta de Jelly para tu referencia.
Leaky Nun

@LeakyNun Está usando un enfoque diferente, que no creo que sea más corto que el tuyo. Pero el_BL$N parecía bastante largo ...
jimmy23013

¿Entonces, básicamente, su código es "piso a la potencia más cercana de 2, menos 1, doble, dividir por entrada, menos longitud binaria de entrada, negativo"?
Leaky Nun

@LeakyNun Sí ..
jimmy23013

3
Solo marginalmente mejor:BL©2*2_÷+®
Sp3000

4

Java, 135 95 90 bytes

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

Creo que puede deshacerse de la interfaz y simplemente crear una función o lambda. También puede devolver el valor en lugar de imprimirlo en stdout
Frozn

Bien, volveré a implementar con esas reglas.
Shaun Wild

Creo que debería permitirse. Como el OP no especificó nada, creo que se aplican las reglas estándar de E / S.
Frozn

Sí, una función está bien, no necesita un programa completo. Tenga en cuenta que la tabla de clasificación recoge el puntaje en la primera línea, por lo que su puntaje se muestra actualmente como 135 en lugar de 95.
Trichoplax

@trichoplax Sigue siendo el último lugar. Yo culpo personalmente a Java ...
Shaun Wild

3

Python 3, 46 bytes

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

Llámalo como

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

Tuve que revertir la revisión del mapa porque falló para la entrada de 5


3

05AB1E, 9 7 bytes

Código:

L<bJg¹/

Explicación:

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

Pruébalo en línea

Editar: guardado 2 bytes gracias a @Adnan


@Adnan: ¡Gracias! Se olvidó de J.
Emigna

3

C #, 87 bytes

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

Escribí una respuesta de C # porque no la vi. Esta es mi primera publicación en una de estas, así que avíseme si estoy haciendo algo mal.


Bienvenido a Programming Puzzles y Code Golf. Esta es una gran primera respuesta, +1. ¿Podría cambiar doublea floatpara guardar un byte o necesita la precisión?
wizzwizz4

2
@ wizzwizz4 ¡Gracias! Pensé lo mismo, pero Promedio () devuelve un doble. Si cambio mi tipo de retorno a flotante, entonces tengo que lanzar explícitamente el doble y ganar 7 bytes en eso.
Raive

2

JavaScript (ES7), 38 32 bytes

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

Usando la fórmula de @ sp3000 (la versión anterior era una solución recursiva). Versión ES6 para 34 bytes:

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

Explicación de la fórmula: considere el caso de N = 55. Si escribimos los números binarios (verticalmente para ahorrar espacio), obtenemos:

                                11111111111111111111111
                111111111111111100000000000000001111111
        11111111000000001111111100000000111111110000000
    111100001111000011110000111100001111000011110000111
  11001100110011001100110011001100110011001100110011001
0101010101010101010101010101010101010101010101010101010

El tamaño de este rectángulo es nl, por lo que el promedio es solo l, pero debemos excluir los espacios en blanco. Cada fila de espacios en blanco es dos veces más larga que la anterior, por lo que el total es 2 + 4 + 8 + 16 + 32 = 64 - 2 = 2 l - 2.


2

J, 21 17 15 bytes

De 17 bytes a 15 bytes gracias a @Dennis.

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

¿Alguien puede ayudarme a jugar golf? ...

Versión sin golf

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

He intentado un enfoque alternativo, por stringifying la lista de números binarios, y salió con 25 bytes: %~>:@#@([:":10#.[:#:i.)-]. Su solución se ve bastante óptima.
Conor O'Brien

2

Perl 6 ,  34  32 bytes

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

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

Explicación:

{ 
  $_  # 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
}

Prueba:

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

Dyalog APL , 14 bytes

(+/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 bytes

Parece que las relaciones están bien de acuerdo con ¿Qué formatos de número son aceptables en la salida?

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

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

no golfed (y ligeramente reescrito para facilitar la explicación)

(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

vieja respuesta que usaba (flotante):

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

la salida es como:

  • n = 1 => 1.0
  • n = 7 => 2.142857

La cuestión de si las fracciones o las proporciones son aceptables no se había planteado antes. Para este desafío, aceptaré cualquier consenso alcanzado sobre cuál debería ser el valor predeterminado .
Trichoplax

1

Minkolang 0.15 , 23 bytes

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

Pruébalo aquí!

Explicació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.

Implementación bastante directa.


1

JavaScript ES5, 55 bytes

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

Explicación

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

Hoon , 71 bytes

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

... Estoy bastante seguro de que esta es la primera vez que uso los núcleos de coma flotante de Hoon. En realidad, es una implementación escrita en Hoon que se lanza a SoftFloat, ya que los únicos tipos de datos en Hoon son átomos y células.

Crear una función que toma un átomo, r. Cree una lista a partir de [0 .. (r - 1)], asigne un mapa sobre la lista tomando el logaritmo binario del número, luego doble esa lista con ++add. Convierta tanto la salida del pliegue como ra @rq(números de coma flotante de precisión cuádruple) con++sun:rq , y luego divida uno por el otro.

Lo más extraño de este fragmento es :.^rqel final. a:ben Hoon significa "evaluar a en el contexto de b". ++rqes el núcleo que contiene toda la implementación de precisión cuádruple, como una biblioteca. Entonces correr (sun 5):rqes lo mismo que hacer (sun:rq 5).

Afortunadamente, los núcleos en Hoon son como muñecas de anidación; cuando ++rqevalúas el brazo para obtener el núcleo, también agrega todo el stdlib, para que puedas seguir rodando y girando y abriéndote y todas esas cosas divertidas en lugar de quedarte atrapado solo con los brazos definidos ++rq. Desafortunadamente, rq se redefine ++addpara ser una adición de punto flotante, junto con no tener ren su contexto. .(todo el contexto actual), sin embargo.

Al evaluar una expresión en un contexto, el compilador busca primero la profundidad del miembro. En nuestro caso a:[. rq], buscaría en todo el contexto actual aantes de pasar a buscar rq. Entonces addbuscará la función que funciona en los átomos en lugar de los números de coma flotante ... pero también lo hará div. Hoon también tiene una función en la que el uso ^nameignorará la primera referencia encontrada y buscará la segunda.

A partir de ahí, es simplemente usar el azúcar sintáctico de a^bser igual a [a b]para evaluar nuestro fragmento con nuestro contexto actual y la biblioteca flotante de precisión cuádruple, ignorando el div atómico a favor de ++div:rq.

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

1

En realidad, 7 bytes:

;r♂├Σl/

Pruébalo en línea!

Explicación:

;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

Si no fuera por un error que acabo de descubrir, esta solución funcionaría para 6 bytes:

r♂├♂læ

æ es el comando medio incorporado.


¿No son estos 10 bytes? Lo comprobé en bytesizematters.com.
m654

1
@ m654 En realidad no usa UTF-8, usa CP437 (o algo así).
Alex A.

@AlexA. Oh, no lo sabia.
m654

1
@ m654 Bytesizematters utiliza una codificación completamente inventada que no existe (y no puede existir) en la práctica. Para UTF-8, use mothereff.in/byte-counter .
Dennis

@ Dennis Gracias por la información, lo tendré en cuenta.
m654


1

PowerShell v2 +, 64 bytes

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

Implementación muy sencilla de la especificación. Bucles de 0a $n-1con |%{...}. Cada iteración, ingresamos [convert]nuestro número de entrada $_a una base de cadena 2y tomamos su length. Acumulamos eso en $o. Después de los bucles, simplemente dividimos $o/$n, dejando eso en la tubería, y la salida es implícita.

Mientras esto sea así, en realidad es más corto que la fórmula que usan Sp y otros, [math]::Ceiling()y [math]::Log()es ridículamente prolijo. La conversión de base en PowerShell es asquerosa.


1

Perl 5.10, 54 bytes

for(1..<>){$u+=length sprintf"%b",$_;$n++}$u/=$n;say$u

Bastante sencillo. sprintf"%b"es una forma ordenada de generar un número en binario en Perl sin usar bibliotecas adicionales.

Pruébalo en línea!


1

CJam, 13 12 11 bytes

Un byte guardado gracias a @ Sp3000, y otro gracias a @ jimmy23013

rd_,2fbs,\/

Pruébalo en línea!

Explicación

Sencillo. Aplica la definición.

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

Jolf, 10 bytes

/uΜr0xdlBH

Pruébalo aquí!

Explicación

/uΜr0xdlBH
  Μr0x      map range 0..x
      dlBH  over lengths of binary elements
/u          divide sum of this
            by implicit input (x)

1

Swift, 72 bytes

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

2
No necesita llamar a la función, dejarla como una función definida está bien. Bonito primer post.
Rɪᴋᴇʀ

1

J, 15 bytes

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

Este es un verbo monádico, usado de la siguiente manera:

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

Pruébalo aquí!

Explicación

Implementé la especificación de desafío literalmente. Hay otros enfoques, pero todos resultaron ser más largos.

%~[:+/#@#:"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.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.