Python, 183
def S(n):
b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
if n<2:return
while~n&1:n>>=1;a+=1
while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
while a:s+=[c,c*b+e*2][i];i=0;a-=1
print(s)
Saya tidak dapat menjamin ini tetap dalam 2x program optimal untuk angka genap, tetapi efisien. Untuk semua input yang valid 0 <= n < 65536, itu pada dasarnya instan, dan menghasilkan program paling banyak 33 instruksi. Untuk ukuran register sewenang-wenang n(setelah menetapkan konstanta itu), akan membutuhkan O(n)waktu paling banyak dengan 2n+1instruksi.
Logika Biner
Angka ganjil ndapat dihubungi dalam 31 langkah: lakukan y+=x, dapatkan x,y = 1,1, dan terus gandakan xdengan x+=x(untuk penggandaan pertama x+=y, karena xganjil untuk memulai). xakan mencapai setiap kekuatan 2 dengan cara ini (itu hanya shift kiri), dan jadi Anda dapat mengatur bit ymenjadi 1 dengan menambahkan kekuatan yang sesuai dari 2. Karena kita menggunakan register 16-bit, dan setiap bit kecuali untuk yang pertama membutuhkan satu penggandaan untuk mencapai dan satu y+=xuntuk ditetapkan, kita mendapatkan maksimal 31 ops.
Setiap bilangan genap nhanya sejumlah 2, sebut saja a, dikalikan dengan angka ganjil, sebut saja m; yaitu n = 2^a * m, atau setara n = m << a,. Gunakan proses di atas untuk mendapatkan m, lalu atur ulang xdengan menggeser ke kiri sampai menjadi 0. Lakukan x+=yuntuk mengatur x = m, dan kemudian lanjutkan untuk menggandakan x, pertama kali menggunakan x+=ydan kemudian menggunakan x+=x.
Apa pun aitu, dibutuhkan 16-apergeseran xuntuk mendapatkan y=mdan apergeseran tambahan untuk mengatur ulang x=0. aPergeseran lain xakan terjadi setelah x=m. Jadi total 16+ashift digunakan. Ada 16-abit hingga yang perlu diatur untuk mendapatkan m, dan masing-masing akan mengambil satu y+=x. Akhirnya kita membutuhkan langkah tambahan kapan x=0harus mengaturnya ke m x+=y,. Jadi dibutuhkan paling banyak 33 langkah untuk mendapatkan angka genap.
Anda dapat, tentu saja, menggeneralisasi ini ke register ukuran apa pun, dalam hal ini selalu dibutuhkan paling banyak 2n-1dan 2n+1ops untuk nbilangan bulat ganjil dan genap , masing-masing.
Optimalitas
Algoritma ini menghasilkan program yang mendekati optimal (yaitu di dalam 2n+2jika nadalah jumlah minimum langkah) untuk angka ganjil. Untuk bilangan ganjil tertentu n, jika mbit ke-1 adalah yang terdepan, maka setiap program mengambil setidaknya mlangkah untuk sampai ke , x=natau y=nkarena operasi yang meningkatkan nilai register paling cepat adalah x+=xatau y+=y(yaitu penggandaan) dan dibutuhkan mpenggandaan untuk mencapai yang mbit th dari 1. Sejak algoritma ini memakan waktu paling 2mlangkah (paling banyak dua per dua kali lipat, satu untuk pergeseran dan satu y+=x), setiap ganjil diwakili dekat-optimal.
Bahkan angkanya tidak begitu baik, karena selalu menggunakan 16 ops untuk mengatur ulang xsebelum yang lain, dan 8, misalnya, dapat dicapai dalam 5 langkah.
Menariknya, algoritma di atas tidak pernah menggunakan y+=ysama sekali, karena yselalu dibuat aneh. Dalam hal ini, ia sebenarnya dapat menemukan program terpendek untuk rangkaian terbatas hanya 3 operasi.
Pengujian
# Do an exhaustive breadth-first search to find the shortest program for
# each valid input
def bfs():
d = {(0,1):0}
k = 0xFFFF
s = set(range(k+1))
current = [(0,1)]
nexts = []
def add(pt, dist, n):
if pt in d: return
d[pt] = dist
s.difference_update(pt)
n.append(pt)
i = 0
while len(s) > 0:
i += 1
for p in current:
x,y = p
add((x,x+y&k), i, nexts)
add((y,x+y&k), i, nexts)
if y%2 == 0: add(tuple(sorted((x,y+y&k))), i, nexts)
if x%2 == 0: add(tuple(sorted((x+x&k,y))), i, nexts)
current = nexts
nexts = []
print(len(d),len(s))
# Mine (@rationalis)
def S(n):
b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
if n<2:return ''
while~n&1:n>>=1;a+=1
while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
while a:s+=[c,c*b+e*2][i];i=0;a-=1
return s
# @CChak's approach
def U(i):
if i<1:return ''
return U(i//2)+'y+=y\n' if i%4==0 else U(i-1)+'y+=x\n'
# Use mine on odd numbers and @CChak's on even numbers
def V(i):
return S(i) if i % 2 == 1 else U(i)
# Simulate a program in the hypothetical machine language
def T(s):
x,y = 1,0
for l in s.split():
if l == 'x+=x':
if x % 2 == 1: return 1,0
x += x
elif l == 'y+=y':
if y % 2 == 1: return 1,0
y += y
elif l == 'x+=y': x += y
elif l == 'y+=x': y += x
x %= 1<<16
y %= 1<<16
return x,y
# Test a solution on all values 0 to 65535 inclusive
# Max op limit only for my own solution
def test(f):
max_ops = 33 if f==S else 1000
for i in range(1<<16):
s = f(i); t = T(s)
if i not in t or len(s)//5 > max_ops:
print(s,i,t)
break
# Compare two solutions
def test2(f,g):
lf = [len(f(i)) for i in range(2,1<<16)]
lg = [len(g(i)) for i in range(2,1<<16)]
l = [lf[i]/lg[i] for i in range(len(lf))]
print(sum(l)/len(l))
print(sum(lf)/sum(lg))
# Test by default if script is executed
def main():
test()
if __name__ == '__main__':
main()
Saya menulis tes sederhana untuk memeriksa apakah solusi saya memang menghasilkan hasil yang benar, dan tidak pernah melewati 33 langkah, untuk semua input yang valid ( 0 <= n < 65536).
Selain itu, saya mencoba melakukan analisis empiris untuk membandingkan output solusi saya terhadap output optimal - namun, ternyata pencarian pertama yang terlalu luas tidak efisien untuk mendapatkan panjang output minimum untuk setiap input yang valid n. Misalnya, menggunakan BFS untuk menemukan output n = 65535tidak berakhir dalam jumlah waktu yang wajar. Meskipun demikian, saya telah meninggalkan bfs()dan terbuka untuk saran.
Saya lakukan, bagaimanapun, menguji solusi saya sendiri terhadap @ CChak (diimplementasikan di Python di sini sebagai U). Saya perkirakan tambang saya akan menjadi lebih buruk, karena secara drastis tidak efisien untuk angka genap yang lebih kecil, tetapi rata-rata di seluruh jajaran dalam dua cara, tambang menghasilkan keluaran panjang rata-rata 10,8% hingga 12,3% lebih pendek. Saya pikir mungkin ini karena efisiensi yang lebih baik dari solusi saya sendiri pada angka ganjil, jadi Vgunakan milik saya pada angka ganjil dan @ CChak pada angka genap, tetapi Vada di antara (sekitar 10% lebih pendek dari U, 3% lebih lama dari S).
x+=xhanya sah jikaxadil? Juga untuk program terpendek saya pikir sesuatu seperti BFS bisa berfungsi.