Número binario más corto en rango

8

Dados dos números decimales arbitrariamente precisos 0 ≤ x < y ≤ 1, calcule el número binario más corto (en dígitos) b tal que xb < y .

Imprima los dígitos binarios de b después del punto binario como una matriz o una cadena de ceros y unos. Tenga en cuenta que la matriz vacía significa 0.0, en virtud de eliminar ceros finales. Esto también asegura que haya una respuesta correcta única para cualquier rango.

Si no está familiarizado con los números fraccionarios binarios, funcionan igual que los números decimales:

Base 10   0.625 = 0.6 + 0.02 + 0.005 = 6 x 10^-1  +  2 x 10^-2  +  5 x 10^-3
Base  2   0.101 = 0.1 + 0.00 + 0.001 = 1 x  2^-1  +  0 x  2^-2  +  1 x  2^-3
                                          |             |             |
                                          v             v             v
Base 10                        0.625 =   0.5      +     0       +   0.125

Las incorporaciones que trivializan este problema no están permitidas.

Ejemplos:

0.0, 1.0 -> ""
0.1, 1.0 -> "1"
0.5, 0.6 -> "1"
0.4, 0.5 -> "0111"

El código más corto gana.

orlp
fuente
3
¿"Arbitrariamente preciso" significa "dentro de los límites de los tipos de su idioma", o tenemos que apoyar la entrada de (0.98983459823945792125172638374187268447126843298479182647, 0.98983459823945792125172638374187268447126843298479182648)? Además, los casos de prueba serían útiles.
Pomo de la puerta
@Doorknob Arbitrariamente preciso significa que su respuesta debería funcionar para cualquier entrada, hasta los límites de la máquina física (memoria). Entonces sí, esa entrada debe ser compatible.
orlp
¿Una especie de engaño ?
Martin Ender
@ MartinBüttner Muy cerca (no lo sabía), pero esta pregunta requiere precisión arbitraria y salida como bits.
orlp
1
Aaaah, el intervalo medio abierto superior x ≤ b <y es difícil de tratar, sería mucho más fácil con x <b ≤ y.
xnor

Respuestas:

2

CJam, 46

q'.-_,:M;S/{3a.+M'0e]~GM#*AM(#/(2b}/_@.=0#)<2>

Pruébalo en línea

Explicación:

La idea general es: multiplique ambos números por 10 algún exponente lo suficientemente grande como para obtener enteros, multiplique nuevamente por 2 otro exponente lo suficientemente grande como para "dejar espacio" para los dígitos binarios en forma de enteros, dividir enteros por 10 el primer exponente , disminuir el números (para llegar al caso "x <b ≤ y") y convertir los resultados a la base 2. Encuentre el primer dígito diferente (será 0 en el primer número y 1 en el segundo número) e imprima todos los dígitos desde el segundo número hasta e incluido ese.

Antes de comenzar con las multiplicaciones, estoy agregando 3 a las partes enteras para asegurarme de que los resultados tengan el mismo número de dígitos binarios (sin ceros a la izquierda) después de disminuir. Al final, estoy omitiendo los primeros 2 dígitos binarios para compensar.

q          read the input as a string
'.-        remove the dots
_,         duplicate and get the string length
:M;        store in M and pop; M-1 will be the first exponent
S/         split by space
{…}/       for each number (in string form)
  3a.+     add 3 to the first digit (vectorized-add [3] to the string)
  M'0e]    pad to the right with '0's up to length M
            this is like multiplying the decimal number with 10^(M-1)
            but done as a string operation
  ~        evaluate the result as an integer
  GM#*     multiply by 16^M (G=16) = 2^(4*M) -- 4*M is the second exponent
  AM(#/    divide by 10^(M-1) (A=10)
  (2b      decrement and convert to base 2 (array of digits)
_          duplicate the 2nd array
@          bring the first array to the top
.=         vectorized-compare the arrays (digit by digit)
0#         find the position of the first 0 (meaning digits are not equal)
)<         increment and slice the other copy of the 2nd array before that position
2>         discard the first 2 digits
aditsu renunció porque SE es MALO
fuente
2

Rubí, 138 132 bytes

->x,y{d,*a=->{a.map.with_index{|n,i|n/BigDecimal.new(2)**(i+1)}.inject(:+)||0};[a+=[1],a[-1]=d[]>=y ?0:1]while d[]<x;a}

13 bytes agregados para la -rbigdecimalbandera. Espera entrada como dos BigDecimals.

Ejecución de muestra:

irb(main):029:0> f=->x,y{d,*a=->{a.map.with_index{|n,i|n/BigDecimal.new(2)**(i+1)}.inject(:+)||0};[a+=[1],a[-1]=d[]>=y ?0:1]while d[]<x;a}
=> #<Proc:0x00000001053a10@(irb):29 (lambda)>
irb(main):030:0> f[BigDecimal.new('0.98983459823945792125172638374187268447126843298479182647'),BigDecimal.new('0.98983459823945792125172638374187268447126843298479182648')]
=> [1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1]

Explicación:

->x,y{
d,*a=   # sets d to the following, and a to [] with fancy splat operator
->{     # lambda...
 a.map.with_index{|n,i|       # map over a with indices
  n/BigDecimal.new(2)**(i+1)  # this will return:
                              #  - 0 [ /2**(i+1) ] if n is 0
                              #  - 1   /2**(i+1)   if n is 1
 }.inject(:+)                 # sum
 ||0                          # inject returns nil on empty array; replace with 0
};      # this lambda turns `[0, 1, 1]' into `BigDecimal(0b0.011)'
[       # `[...]while x' is a fancy/golfy way to say `while x;...;end'
 a+=[1],            # add a digit 1 to the array
 a[-1]=d[]>=y ?0:1  # replace it with 0 if we exceeded upper bound
]while d[]<x;       # do this while(below the lower bound)
a       # return the array of digits
}
Pomo de la puerta
fuente
2

Mathematica, 72 bytes

IntegerDigits[#2[[-1,-1]],2,Log2@#]&@@Reap[1//.a_/;Sow@⌈a#⌉>=a#2:>2a]&

Explicación

El método consiste en encontrar el multiplicador de forma más pequeño 2^nque amplíe la brecha entre dos números de entrada para que contenga un número entero.

Por ejemplo, 16*{0.4,0.5} = {6.4,8.}contiene 7, entonces la respuesta es 7/16.

Caso de prueba

%[0.4,0.5]
(* {0,1,1,1} *)
njpipeorgan
fuente
Agradable cosechar y sembrar!
Un Simmons
0

JavaScript (ES6), 144 bytes

f=(x,y,b='',d=s=>s.replace(/\d/g,(n,i)=>(i&&n*2%10)+(s[i+1+!i]>4)).replace(/[.0]+$/,''),n=d(x),m=d(y))=>n?n>'1'||(m||2)<='1'?f(n,m,b+n[0]):b+1:b

Asume la entrada en el formulario 0.<digits>(o 1.<zeros>es aceptable para y). des una función que toma la parte decimal de un número y la duplica, luego recorta los ceros finales. El primer dígito debe estar presente pero se ignora. Convenientemente d("0.0")está vacío y, por lo tanto, esto se usa como prueba para ver si xes una fracción binaria exacta; en este caso bya tiene el resultado. De lo contrario, hay una prueba algo complicada para determinar si el sufijo a 1to bsirve para distinguir entre xy y; Si es así, se devuelve. De lo contrario, el MSB de xtiene el sufijo del resultado y la función se llama a sí misma recursivamente para procesar el siguiente bit.

Si en cambio deseamos que x < b ≤ yla función sea mucho más simple, algo como esto (no probado):

f=(x,y,b='',d=s=>s.replace(/\d/g,(n,i)=>(i&&n*2%10)+(s[i+1+!i]>4)),n=d(x),m=d(y))=>n>='1'||m<'1'?f(n,m,b+n[0]):b+1
Neil
fuente