Menor número binário no intervalo


8

Dado dois números decimais arbitrariamente precisos 0 ≤ x < y ≤ 1, calcule o número binário mais curto (em dígitos) b de modo que xb < y .

Emita os dígitos binários de b após o ponto binário como uma matriz ou uma sequência de zeros e uns. Observe que a matriz vazia significa 0,0, devido à exclusão de zeros à direita. Isso também garante que haja uma resposta correta exclusiva para qualquer intervalo.

Se você não estiver familiarizado com números fracionários binários, eles funcionam como números decimais:

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

Os internos que trivializam esse problema não são permitidos.

Exemplos:

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

O menor código vence.


3
"Arbitrariamente preciso" significa "dentro dos limites dos tipos do seu idioma", ou temos que apoiar a entrada de (0.98983459823945792125172638374187268447126843298479182647, 0.98983459823945792125172638374187268447126843298479182648)? Além disso, os casos de teste seriam úteis.
Maçaneta

@Doorknob Arbitrariamente preciso significa que sua resposta deve funcionar para qualquer entrada, até os limites da máquina física (memória). Então, sim, essa entrada deve ser suportada.
orlp


@ MartinBüttner Muito perto (não sabia disso), mas essa pergunta requer precisão arbitrária e saída como bits.
orlp

1
Ah, é difícil lidar com o intervalo da metade da abertura superior x ≤ b <y, seria muito mais fácil com x <b ≤ y.
Xnor

Respostas:


2

CJam, 46

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

Experimente online

Explicação:

A idéia geral é: multiplique os dois números por 10 algum expoente grande o suficiente para obter números inteiros, multiplique novamente por 2 outro expoente grande o suficiente para "criar espaço" para dígitos binários em forma de número inteiro, divida-o novamente por 10 o primeiro expoente , diminua o números (para chegar ao caso "x <b ≤ y") e converter os resultados na base 2. Encontre o primeiro dígito diferente (será 0 no primeiro número e 1 no segundo número) e imprima todos os dígitos do segundo número até e incluindo esse.

Antes de começar com as multiplicações, estou adicionando 3 às partes inteiras para garantir que os resultados tenham o mesmo número de dígitos binários (sem zeros à esquerda) após decrementar. No final, estou pulando os 2 primeiros dígitos binários 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

2

Ruby, 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 adicionados para o -rbigdecimalsinalizador. Espera entrada como dois BigDecimals.

Exemplo de execução:

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]

Explicação:

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

2

Mathematica, 72 bytes

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

Explicação

O método é encontrar o menor multiplicador de forma 2^nque amplia o intervalo entre dois números de entrada, para que ele contenha um número inteiro.

Por exemplo, 16*{0.4,0.5} = {6.4,8.}contém 7, então a resposta é 7/16.

Caso de teste

%[0.4,0.5]
(* {0,1,1,1} *)

Colher agradável e porca!
Um 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

Assume a entrada no formulário 0.<digits>(ou 1.<zeros>é aceitável para y). dé uma função que pega a parte decimal de um número e a dobra e apara os zeros à direita. O dígito inicial deve estar presente, mas é ignorado. Convenientemente d("0.0")está vazio e, portanto, é usado como teste para verificar se xé uma fração binária exata; neste caso, bjá mantém o resultado. Caso contrário, há um teste um pouco complicado para determinar se o sufixo a 1a bserve para distinguir entre xe y; se sim, isso é retornado. Caso contrário, o MSB de xé sufixado no resultado e a função se chama recursivamente para processar o próximo bit.

Se, em vez disso, desejamos que x < b ≤ ya função seja muito mais simples, algo como isto (não testado):

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.