Nomor biner terpendek dalam jangkauan

8

Mengingat dua sewenang-wenang yang tepat desimal angka 0 ≤ x < y ≤ 1, menghitung terpendek (dalam angka) biner nomor b sehingga xb < y .

Keluarkan digit biner b setelah titik biner sebagai array atau string nol dan satu. Perhatikan bahwa array kosong berarti 0,0, berdasarkan penghapusan nol trailing. Ini juga memastikan bahwa ada jawaban unik yang benar untuk rentang apa pun.

Jika Anda tidak terbiasa dengan angka pecahan biner, angka itu berfungsi seperti angka desimal:

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

Built-in yang meremehkan masalah ini tidak diizinkan.

Contoh:

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

Kode terpendek menang.

orlp
sumber
3
Apakah "tepat secara sewenang-wenang" berarti "dalam batas jenis bahasa Anda," atau apakah kita harus mendukung masukan (0.98983459823945792125172638374187268447126843298479182647, 0.98983459823945792125172638374187268447126843298479182648)? Juga, uji kasus akan sangat membantu.
Gagang Pintu
@ Doorknob Tepat secara sewenang-wenang berarti bahwa jawaban Anda harus bekerja untuk input apa pun, hingga batas mesin fisik (memori). Jadi ya, input itu harus didukung.
orlp
Semacam dupe ?
Martin Ender
@ MartinBüttner Benar-benar dekat (tidak menyadarinya), tetapi pertanyaan ini membutuhkan ketepatan dan keluaran sewenang-wenang sebagai bit.
orlp
1
Aaaah interval setengah terbuka atas x ≤ b <y sulit untuk ditangani, itu akan jauh lebih mudah dengan x <b ≤ y.
xnor

Jawaban:

2

CJam, 46

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

Cobalah online

Penjelasan:

Gagasan umum adalah: kalikan kedua angka dengan 10 eksponen cukup besar untuk mendapatkan bilangan bulat, kalikan lagi dengan 2 eksponen cukup besar untuk "memberi ruang" untuk digit biner dalam bentuk bilangan bulat, integer-bagi kembali dengan 10 eksponen pertama , kurangi angka (untuk sampai ke kasus "x <b ≤ y") dan mengonversi hasilnya menjadi basis 2. Temukan digit berbeda pertama (akan menjadi 0 pada angka pertama dan 1 pada angka kedua), dan cetak semua digit dari nomor kedua hingga dan termasuk yang itu.

Sebelum memulai dengan perkalian, saya menambahkan 3 ke bagian integer untuk memastikan bahwa hasilnya memiliki jumlah digit biner yang sama (tanpa nol di depan) setelah dikurangi. Pada akhirnya, saya melewatkan 2 digit biner pertama untuk mengkompensasi.

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 berhenti karena SE adalah JAHAT
sumber
2

Ruby, 138 132 byte

->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 byte ditambahkan untuk -rbigdecimalbendera. Mengharapkan input sebagai dua BigDecimals.

Contoh dijalankan:

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]

Penjelasan:

->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
}
Gagang pintu
sumber
2

Mathematica, 72 byte

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

Penjelasan

Metode ini adalah untuk menemukan pengganda bentuk terkecil 2^n yang memperbesar kesenjangan antara dua angka input sehingga berisi bilangan bulat.

Misalnya 16*{0.4,0.5} = {6.4,8.}berisi7 , jadi jawabannya adalah 7/16.

Kasus cobaan

%[0.4,0.5]
(* {0,1,1,1} *)
njpipeorgan
sumber
Nice Reap and Sow!
A Simmons
0

JavaScript (ES6), 144 byte

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

Mengasumsikan input dalam formulir 0.<digits>(atau 1.<zeros>dapat diterima untuk y). dadalah fungsi yang mengambil bagian desimal dari angka dan menggandakannya, lalu memangkas angka nol. Digit terdepan harus ada tetapi diabaikan. Nyaman d("0.0")kosong, dan karena itu ini digunakan sebagai tes untuk melihat apakah xfraksi biner yang tepat; dalam hal ini bsudah memegang hasilnya. Jika tidak, ada tes agak berbelit-belit untuk menentukan apakah suffixing sebuah 1ke bservis untuk membedakan antara xdan y; jika demikian dikembalikan. Kalau tidak, MSB dari xsuffixed ke hasil dan fungsi memanggil dirinya secara rekursif untuk memproses bit berikutnya.

Jika sebaliknya kita menginginkan x < b ≤ yfungsi lebih sederhana, sesuatu seperti ini (belum diuji):

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
sumber