Menghasilkan ekspresi dasar-bukti

21

Latar Belakang

Dalam beberapa kemungkinan masa depan, dunia akan mengkonversi sistem numerik mereka dari desimal (basis 10 atau b10) ke beberapa basis lain (biner b2, oktal b8, heksadesimal b16, atau bahkan unary b1, dalam hal ini kami mengacaukan!). Jadi, dalam persiapan untuk acara yang mengubah dunia ini, Anda memutuskan untuk membuktikan semua program Anda. Ini dapat dilakukan dengan hanya menggunakan 0s dan s tunggal 1dalam hubungannya dengan operator untuk mengganti konstanta angka yang ada.

Namun, hanya ada satu masalah: Anda memiliki banyak program untuk diubah, dan mengonversi setiap angka secara manual ke ekspresi akan membutuhkan waktu berminggu-minggu! Dengan demikian, Anda memutuskan untuk menulis sebuah program (atau fungsi) untuk memutuskan untuk Anda ekspresi apa yang harus diganti setiap angka.

Memasukkan

Input akan berupa bilangan bulat positif. Kode Anda harus mampu menangani bilangan bulat apa pun hingga 1000.

(Jika kode Anda mendukung desimal dan / atau input negatif, lihat Penilaian di bawah ini.)

Keluaran

Kode Anda harus menampilkan ekspresi yang mengevaluasi input dalam setidaknya satu bahasa. Ini mungkin bahasa apa pun; tidak harus sama dengan yang ditulis oleh program atau fungsi Anda. Juga, ungkapan ini tidak harus berupa program atau fungsi lengkap.

Untuk kejelasan, output mungkin mengandung operasi-operasi berikut:

  • kenaikan / penurunan
  • tambah / jumlah
  • kurangi / negasikan
  • kalikan / gandakan (hanya jika itu tidak secara langsung melibatkan nomor 2!)
  • bagi / modulo
  • eksponen / logaritma
  • square / sqrt (sekali lagi, hanya jika ini tidak secara langsung melibatkan nomor 2!)
  • operasi bitwise (bOR, bAND, bNOT, bXOR, bit-shift)
  • pengaturan / mendapatkan variabel
  • manipulasi tumpukan

Anda tidak boleh menggunakan eval()atau fungsi serupa dalam output. Anda juga tidak dapat menggunakan dalam output fungsi apa pun yang melakukan tindakan selain yang disebutkan di atas.

Oh, dan satu hal lagi: karena kita ingin output menjadi valid dalam basis sebanyak mungkin, satu-satunya konstanta angka yang dikandungnya adalah 0dan 1. Angka seperti 10(sepuluh) tidak diizinkan, kecuali bahasa menafsirkannya sebagai a 1dan a 0. Menggunakan string untuk memuat angka juga tidak diperbolehkan, seperti halnya menggunakan karakter seperti CJam's A- K(yang mewakili 10- 20).

Kasus uji

(Semua output dalam JavaScript, tetapi dapat bekerja dalam bahasa lain.)

Input 1:

2

Output yang mungkin 1:

1+1

Input 2:

13

Kemungkinan hasil 2:

(a=1+1+1)*a+a+1

Input 3:

60

Kemungkinan hasil 3:

(b=(a=1+1+1+1)*a)*a-a

Input 4:

777

Kemungkinan hasil 4:

(c=(b=((a=1+1+1+1)*a-a+1)*a)*a+b)+c+c-a+1

Input 5:

1000

Kemungkinan hasil 5:

Math.pow((a=1+1+1)*a+1,a)

Mencetak gol

Tujuan dari tantangan ini adalah untuk mempersingkat output kode Anda sebanyak mungkin. Skor Anda akan dihitung dengan cara ini:

  • Skor dasar: Penghitungan byte rata-rata dari semua output untuk bilangan bulat 1 hingga 1000.

  • Skor desimal: Jika kode Anda mendukung setidaknya 3 tempat desimal, ini adalah jumlah byte rata-rata dari semua output dari urutan angka mulai 0.001dan berakhir pada 1000, meningkat 1.001setiap kali. 0.001, 1.002, 2.003...998.999, 1000.000Kemudian ambil potongan 50% dari skor ini.

  • Nilai negatif: Jika kode Anda mendukung angka negatif dan nol, ini adalah rata-rata byte-output dari semua bilangan bulat dari -1000hingga 0. Kemudian ambil potongan 10% dari skor ini.

(Cara termudah untuk menghitung ini kemungkinan akan menjadi loop dengan program / fungsi Anda di dalamnya.)

Skor akhir Anda adalah rata-rata yang mana dari rumus di atas berlaku.

Jika output non-deterministik (yaitu agak acak; beberapa kali berjalan dengan input yang sama menghasilkan beberapa output unik), maka skor untuk setiap input ditentukan oleh output terbesar dari sepuluh berjalan pada CPU saya.

Juga, karena Anda tidak tahu betapa berharganya data komputer di masa depan, jumlah byte kode generator Anda harus kurang dari 512 byte.

Skor terendah dalam dua minggu (pada 30 September) akan dinyatakan sebagai pemenang. Selamat kepada pemenang Anda, @ThomasKwa !


Papan peringkat

Untuk memastikan jawaban Anda muncul dengan benar, silakan mulai dengan tajuk ini:

# Language name/Other language name, X points

Di mana Xskor jawaban Anda. Contoh:

# CJam/Pyth, 25.38 points

Jika Anda memiliki pertanyaan atau saran, beri tahu saya. Semoga berhasil!

Produksi ETH
sumber
Bisakah saya menggunakan variabel yang tahan 0atau 1secara default?
Dennis
@ Dennis Saya tidak melihat masalah dengan itu, jadi silakan!
Produksi ETH
Saya berasumsi saya tidak bisa melakukan konversi basis antara basis 2 dan basis default.
Biru
@muddyfish Tidak, tidak ada konversi basis yang diizinkan dalam output.
ETHproduk
Saya kira kita juga tidak diperbolehkan menggunakan sesuatu seperti Integer.parseInt("1000", 1+1+1+1+1+1+1+1+1+1)? Saya cukup yakin parseInthanya menggunakan operasi yang diizinkan ;-)
Paŭlo Ebermann

Jawaban:

10

Kode mesin Python / Zilog Z80, 11.653 11.488

import math,numpy as np
def R(n):
    if n==0:return []
    if n<0:return -R(-n)
    e=int(math.log(n,2))
    if n >= 5/3 * 2**e:
        return np.append(2**(e+1),-R(2**(e+1)-n))
    return np.append(2**e,R(n-2**e))

def strR(n):
    b = R(n)
    s = ""
    if n==0:return s
    e=max(abs(b))
    while e:
        if e in b:s+="#"
        elif -e in b:s+="+"
        s+=")"
        e//=2
    return s[:-1]

Bonus: Angka negatif.

Mengasumsikan bahwa hlpasangan register awalnya memegang 0, dan mengembalikan hasilnya dalam hl.

Hanya tiga instruksi ini yang digunakan:

ASCII   Hex    Instruction
--------------------------
#       23     inc hl
)       29     add hl,hl
+       2B     dec hl

Kami menggunakan sedikit modifikasi dari representasi biner seimbang BBR2 berbobot minimum . Karena BBR2 meminimalkan bobot (jumlah digit bukan nol), tetapi kami ingin meminimalkan bobot plus jumlah pergeseran bit, kami mengubah konstanta dalam algoritma dari 3/2menjadi 5/3.

Untuk menghitung skor dan memverifikasi, gunakan kode ini:

def verify(n):
v = 0
for c in strR(n):
    if c=="#":v += 1
    elif c=="+":v -= 1
    else: v *= 2
return v==n

print(0.5*(sum([len(strR(n)) for n in range(1,1001)])/1000 + \
           sum([len(strR(n)) for n in range(-1000,1)])/1001 * 0.9))

print(all([verify(n) for n in range(-1000,1001)]))

Contoh output:

strR(486)
         '#)))))+)+))+)'

Atau dalam perakitan:

inc hl \ add hl,hl \ add hl,hl \ add hl,hl \ add hl,hl \ add hl,hl \ dec hl \ add hl,hl \ dec hl \ add hl,hl \ add hl,hl \ dec hl \ add hl,hl

Lebih banyak contoh program:

-256  +))))))))
-255  +))))))))#
-254  +)))))))#)
-253  +)))))))#)#
-252  +))))))#))
-251  +))))))#))#
-250  +))))))#)#)
-249  +)))))#)))+
-248  +)))))#)))
-247  +)))))#)))#
-246  +)))))#))#)
-245  +)))))#))#)#
-244  +)))))#)#))
-243  +)))))#)#))#
-242  +))))#)))+)
-241  +))))#))))+

  -5  +))+
  -4  +))
  -3  +)+
  -2  +)
  -1  +
   0  
   1  #
   2  #)
   3  #)#
   4  #))
   5  #))#

Kemungkinan pengoptimalan: aturan OP bahwa instruksi inc hdan dec h, yang secara langsung mengubah byte atas hl, adalah ilegal, tetapi sla hdan tidak berdokumen sl1 h(bit kiri bergeser 1 pada hshift itu di 0dan 1masing - masing) diizinkan. sla hdan sl1 hmasing-masing dua byte, tetapi terkadang dapat mempersingkat output.

lirtosiast
sumber
Sangat bagus, terendah sejauh ini! Saya kira ini adalah satu contoh di mana kode mesin murni berguna. ;)
ETHproduksi
2
+1 ini mungkin tidak ada duanya. Juga untuk jenius menggunakan kode mesin (pada cpu dengan set instruksi sebagian besar 8 bit dan beberapa register 16 bit.)
Level River St
Aneh bagaimana +menerjemahkannya dec. Saya terus membaca contoh negatif yang salah.
ETHproduksi
9

CJam / CJam, 143.263 42.713 28.899 23.901 21.903 20.468

ri
[
    ['X\2b1>e`{~{"1)*)"*}{_({(')*1\"m<"}{"1)*"*}?}?}/]s
    "X1)*"/"1)"*
    "1)1)*"/"1)))"*
    "X1)m<"/"1)))"*
    _"1)"/("1):Y"+\'Y*+
]
{,}$0=

Tidak ada bonus yang berlaku.

Cobalah online: contoh jalankan | skor kalkulator | verifikasi

Contoh berjalan

   1 X
   2 1)
   3 1))
   4 1)))
   5 1))))
   6 1))1)*
   7 1))1)*)
   8 X1))m<
   9 1)))1)*)
  10 1))))1)*
  11 1))))1)*)
  12 1))1)m<
  13 1))1)*1)*)
  14 1))1)*)1)*
  15 1))1)*)1)*)
  16 X1)))m<
  17 X1))m<1)*)
  18 1)))1)*)1)*
  19 1)))1)*)1)*)
  20 1))))1)m<
 981 1):Y)Y*)Y*)Y*Y*)Y*Y*)Y*Y*)
 982 1):Y)Y*)Y*)Y*Y*)Y*Y*)Y*)Y*
 983 1):Y)Y*)Y*)Y*Y*)Y*Y*)Y*)Y*)
 984 1):Y)Y*)Y*)Y*Y*)Y*)Y)m<
 985 1):Y)Y*)Y*)Y*Y*)Y*)Ym<Y*)
 986 1):Y)Y*)Y*)Y*Y*)Y*)Y*Y*)Y*
 987 1):Y)Y*)Y*)Y*Y*)Y*)Y*Y*)Y*)
 988 1):Y)Y*)Y*)Y*Y*)Y*)Y*)Ym<
 989 1):Y)Y*)Y*)Y*Y*)Y*)Y*)Y*Y*)
 990 1):Y)Y*)Y*)Y*Y*)Y*)Y*)Y*)Y*
 991 1):Y)Y*)Y*)Y*Y*)Y*)Y*)Y*)Y*)
 992 1):Y)Y*)Y*)Y*)Y)))m<
 993 1):Y)Y*)Y*)Y*)Y))m<Y*)
 994 1):Y)Y*)Y*)Y*)Y)m<Y*)Y*
 995 1):Y)Y*)Y*)Y*)Y)m<Y*)Y*)
 996 1):Y)Y*)Y*)Y*)Ym<Y*)Ym<
 997 1):Y)Y*)Y*)Y*)Ym<Y*)Y*Y*)
 998 1):Y)Y*)Y*)Y*)Ym<Y*)Y*)Y*
 999 1):Y)Y*)Y*)Y*)Ym<Y*)Y*)Y*)
1000 1):Y)Y*)Y*)Y*)Y*Y*)Y)m<
Dennis
sumber
Kata saya, itu cepat! Tautan tidak berfungsi di Firefox.
ETHproduk
Karena ini bukan kode golf, saya mengganti masing %- masing dengan ekspresi yang lebih panjang. Tautan harus berfungsi sekarang.
Dennis
Input 34 memberi 1. Di input mana ia bekerja lebih baik
Kishan Kumar
2
@KishanKumar Verifikasi menguji semua 1000 kemungkinan input. Output 1 menunjukkan bahwa perbandingan berhasil.
Dennis
Bisakah Anda menambahkan beberapa contoh output?
Paŭlo Ebermann
3

ß / BrainFuck, 34,201 poin

Sumber ß (194B):

E='++[------>+<]>++'°\c[1]<0°{E&='.'µA=ß"-ß°°c[1]),'')µE&='+++'°/B=1°(A[0]°\A[B]='.'°{µE&='--.++'°]E&=ß~A'+',A[B])&'.'&ß~A'-',A[B])°}°)°'ß"&E,'+-')+ß"&E,'-+')>0µE=ß"'ß"'E,'-+',''),'+-','')°!€E)

Jika seseorang tertarik, saya akan menambahkan penjelasan. Output BF sudah cukup dioptimalkan, tapi saya kira saya bisa menggunakan 318B kode ß yang tersisa untuk diimplementasikan

  • optimasi loop-nesting,
  • lebih banyak jalan pintas 8bit,
  • penghapusan tabrakan operator .

Sampel:

Berjalan di windows:

$ sharps encode.ss 42
++[------>+<]>+++++++++.--.--

$ sharps encode.ss -42
++[------>+<]>++.+++++++.--.--

$ sharps encode.ss 1.427
++[------>+<]>++++++.---.++++++.--.+++++.-------

$ sharps encode.ss -946.427
++[------>+<]>++.++++++++++++.-----.++.--------.++++++.--.+++++.-------

Berjalan di linux:

$ WINEDEBUG=-all wine sharps source.ss -4.72
++[------>+<]>++.+++++++.------.+++++++++.-----.--

Validasikan dalam penerjemah BF online .

Skor:

  1. Rata-rata dasar = 37.495.
  2. Rata-rata desimal = 60.959 * 0.5 = ~30.48.
  3. Rata-rata negatif. = 38.4765234765235 * 0.9 = ~34.629
  4. Rata-rata di atas, skor akhir = (37.495 + 30.48 + 34.629)/3 = 34.201.
mınxomaτ
sumber
1
Saya selalu suka melihat bahasa baru yang dibuat orang. :) Terima kasih atas pemecahan skornya! Saya ingin memberikan lebih banyak bonus pada bagian desimal, jadi saya telah mengubah pengurangan dari 40% menjadi 50%.
ETHproduk
@ ETHproductions Ya, saya akan mencoba menyiapkan penerjemah online untuk ini. Ada sekitar 435 operator yang sangat abstrak, tambahan 9,9k dapat didefinisikan ;-). Saya telah memperbaiki perhitungan (semoga).
mınxomaτ
3

Ruby / Ruby, 29.77885

31.873 * 0,9 (negatif) 30,872 (positif).

Strategi dasar adalah representasi basis 3 simetris ("terner seimbang"), yaitu ketika digit -1,0,1bukan0,1,2

#function
f=->n{m=n  
  a='0' 
  7.times{|i|
    r=m%3;r-=r/2*3
    m=(m-r)/3
    #produce expression: replace 0 with (0*x+-1)
    #only add 0*x if there are higher base 3 digits to follow.
    #only add (..+-1) if the current base 3 digit is nonzero. 
    a.sub!('0',['','(','('][r]+(m.abs>0?'0*x':'')+['','+1)','-1)'][r])
  }
  #tidy up expression
  a.sub!('(-1)*','-')          #remove internal (-1)*
  a.sub!('(+1)*','')           #remove internal (+1)*
  a[-1]==')' && a=a[1..-2]     #remove unnecessary global brackets
  a.sub!('x','(x=1+1+1)')      #find the first x and define it as 1+1+1=3
  #special cases for small numbers 
  n.abs<8 && a=n==0?'0':['','1'+'+1'*(n-1).abs,'-1'*n.abs][n<=>0] 
  a 
}

#call like this
(1..1000).each{|p|
b=f.call(p)
puts b

Inilah output dari 0 hingga 40 sebelum pembersihan

(+1)
((+1)*x-1)
(+1)*x
((+1)*x+1)
(((+1)*x-1)*x-1)
((+1)*x-1)*x
(((+1)*x-1)*x+1)
((+1)*x*x-1)
(+1)*x*x
((+1)*x*x+1)
(((+1)*x+1)*x-1)
((+1)*x+1)*x
(((+1)*x+1)*x+1)
((((+1)*x-1)*x-1)*x-1)
(((+1)*x-1)*x-1)*x
((((+1)*x-1)*x-1)*x+1)
(((+1)*x-1)*x*x-1)
((+1)*x-1)*x*x
(((+1)*x-1)*x*x+1)
((((+1)*x-1)*x+1)*x-1)
(((+1)*x-1)*x+1)*x
((((+1)*x-1)*x+1)*x+1)
(((+1)*x*x-1)*x-1)
((+1)*x*x-1)*x
(((+1)*x*x-1)*x+1)
((+1)*x*x*x-1)
(+1)*x*x*x
((+1)*x*x*x+1)
(((+1)*x*x+1)*x-1)
((+1)*x*x+1)*x
(((+1)*x*x+1)*x+1)
((((+1)*x+1)*x-1)*x-1)
(((+1)*x+1)*x-1)*x
((((+1)*x+1)*x-1)*x+1)
(((+1)*x+1)*x*x-1)
((+1)*x+1)*x*x
(((+1)*x+1)*x*x+1)
((((+1)*x+1)*x+1)*x-1)
(((+1)*x+1)*x+1)*x
((((+1)*x+1)*x+1)*x+1)

Dan setelah pembersihan

0
1
1+1
1+1+1
1+1+1+1
1+1+1+1+1
1+1+1+1+1+1
1+1+1+1+1+1+1
(x=1+1+1)*x-1
(x=1+1+1)*x
(x=1+1+1)*x+1
((x=1+1+1)+1)*x-1
((x=1+1+1)+1)*x
((x=1+1+1)+1)*x+1
(((x=1+1+1)-1)*x-1)*x-1
(((x=1+1+1)-1)*x-1)*x
(((x=1+1+1)-1)*x-1)*x+1
((x=1+1+1)-1)*x*x-1
((x=1+1+1)-1)*x*x
((x=1+1+1)-1)*x*x+1
(((x=1+1+1)-1)*x+1)*x-1
(((x=1+1+1)-1)*x+1)*x
(((x=1+1+1)-1)*x+1)*x+1
((x=1+1+1)*x-1)*x-1
((x=1+1+1)*x-1)*x
((x=1+1+1)*x-1)*x+1
(x=1+1+1)*x*x-1
(x=1+1+1)*x*x
(x=1+1+1)*x*x+1
((x=1+1+1)*x+1)*x-1
((x=1+1+1)*x+1)*x
((x=1+1+1)*x+1)*x+1
(((x=1+1+1)+1)*x-1)*x-1
(((x=1+1+1)+1)*x-1)*x
(((x=1+1+1)+1)*x-1)*x+1
((x=1+1+1)+1)*x*x-1
((x=1+1+1)+1)*x*x
((x=1+1+1)+1)*x*x+1
(((x=1+1+1)+1)*x+1)*x-1
(((x=1+1+1)+1)*x+1)*x
(((x=1+1+1)+1)*x+1)*x+1
Level River St
sumber
Saya percaya itu disebut "terner seimbang".
lirtosiast
@ThomasKwa diedit, terima kasih
Level River St
3

Ceylon / Ceylon, 49,86 40,95 poin

Versi ketiga menggunakan Ceylon 1.2 untuk generator dan 509 byte kode:

import ceylon.language{S=String,I=Integer,e=expand}S q(I n)=>n==0then"0"else(n<0then"-"+p(-n,"-")else p(n,"+"));variable Map<[I,S],S>c=map{};S p(I n,S s){S v=c[[n,s]]else(n<8then s.join([1].repeat(n)))else(let(a="+-".replace(s,""))e(e{for(x in 2..8)let(l=(n^(1.0/x)).integer){for(r in l:2)if(r>1)let(w=r^x){if(w-n<n)"("+p(r,"+")+")^("+p(x,"+")+")"+(w<n then s+p(n-w,s)else(n<w then a+p(w-n,a)else""))}}}).reduce<S>((x,y)=>x.size<y.size then x else y))else"";c=[n,s]in c then c else map{[n,s]->v,*c};return v;}

Ini turun menjadi 35,22 poin, tapi saya tidak akan menempatkan ini di baris judul karena Celyon 1.2 hanya diterbitkan pada 29 Oktober. Saya tidak berpikir saya akan dapat mengimplementasikan algoritma ini dalam Ceylon 1.1 dalam ukuran ini.). Lebih detail di sana, di sini saya akan menjelaskan versi kedua. (Versi pertama dapat dilihat dalam sejarah - versi ini hanya mendukung angka positif, tetapi cocok dengan 256 byte.)

Versi kedua

Sekarang versi kedua, yang mendukung bilangan bulat negatif (dan 0), dan umumnya menghasilkan keluaran yang sedikit lebih pendek dengan menggunakan tambahan -. (Versi ini sebenarnya menggunakan panjang yang diizinkan, yang pertama mencoba untuk tetap di bawah 256 byte, bukan 512.)

String proof(Integer n) {
    if (n == 0) { return "0"; }
    if (n < 0) { return "-" + p(-n, "-"); }
    return p(n, "+");
}
String p(Integer n, String sign) {
    if (n < 9) {
        return sign.join([1].repeat(n));
    }
    value anti = (sign == "+") then "-" else "+";
    value root = ((n^0.5) + 0.5).integer;
    return "(" + p(root, "+") + ")^(1+1)" +
       ( (root^2 < n) then sign + p(n - root^2, sign) else
         ((n < root^2) then anti + p(root^2 - n, anti) else ""));
}

Kode memiliki panjang 487, jadi masih ada ruang untuk optimisasi lebih lanjut nanti. (Ada juga banyak cadangan dalam bentuk spasi putih dan nama variabel panjang.)

Skor:

Total positive: 42652
Average positive:42.652
Total negative: 43653
Average negative: 43.60939060939061
With bonus:39.24845154845155
Overall score: 40.95022577422577

Beberapa output sampel:

   27:  21: (1+1+1+1+1)^(1+1)+1+1
   28:  23: (1+1+1+1+1)^(1+1)+1+1+1
   29:  25: (1+1+1+1+1)^(1+1)+1+1+1+1
   30:  27: (1+1+1+1+1)^(1+1)+1+1+1+1+1
   31:  29: (1+1+1+1+1+1)^(1+1)-1-1-1-1-1
   32:  27: (1+1+1+1+1+1)^(1+1)-1-1-1-1
   33:  25: (1+1+1+1+1+1)^(1+1)-1-1-1
   34:  23: (1+1+1+1+1+1)^(1+1)-1-1

  -27:  22: -(1+1+1+1+1)^(1+1)-1-1
  -28:  24: -(1+1+1+1+1)^(1+1)-1-1-1
  -29:  26: -(1+1+1+1+1)^(1+1)-1-1-1-1
  -30:  28: -(1+1+1+1+1)^(1+1)-1-1-1-1-1
  -31:  30: -(1+1+1+1+1+1)^(1+1)+1+1+1+1+1
  -32:  28: -(1+1+1+1+1+1)^(1+1)+1+1+1+1
  -33:  26: -(1+1+1+1+1+1)^(1+1)+1+1+1
  -34:  24: -(1+1+1+1+1+1)^(1+1)+1+1


  993:  65: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1+1)^(1+1)+1+1+1+1+1
  994:  63: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1-1-1
  995:  61: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1-1
  996:  59: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1-1
  997:  57: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1-1
  998:  55: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)-1
  999:  53: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)
 1000:  55: ((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)-(1+1+1+1+1)^(1+1)+1

 -993:  66: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1+1)^(1+1)-1-1-1-1-1
 -994:  64: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1+1+1
 -995:  62: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1+1
 -996:  60: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1+1
 -997:  58: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1+1
 -998:  56: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)+1
 -999:  54: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)
-1000:  56: -((1+1+1+1+1+1)^(1+1)-1-1-1-1)^(1+1)+(1+1+1+1+1)^(1+1)-1

    1:   1: 1
    2:   3: 1+1
    3:   5: 1+1+1
    4:   7: 1+1+1+1
    5:   9: 1+1+1+1+1
    6:  11: 1+1+1+1+1+1
    7:  13: 1+1+1+1+1+1+1
    8:  15: 1+1+1+1+1+1+1+1
    9:  13: (1+1+1)^(1+1)
   10:  15: (1+1+1)^(1+1)+1

    0:   1: 0
   -1:   2: -1
   -2:   4: -1-1
   -3:   6: -1-1-1
   -4:   8: -1-1-1-1
   -5:  10: -1-1-1-1-1
   -6:  12: -1-1-1-1-1-1
   -7:  14: -1-1-1-1-1-1-1
   -8:  16: -1-1-1-1-1-1-1-1
   -9:  14: -(1+1+1)^(1+1)
  -10:  16: -(1+1+1)^(1+1)-1

Seperti yang Anda lihat, yang negatif selalu satu byte (yang -lebih dulu) lebih lama dari yang positif.

Ide dasarnya sama dengan program sebelumnya: temukan kotak di dekat nomor target kami, dan tampilkan akar dan sisanya secara rekursif. Tapi sekarang kami mengizinkan kuadrat kami juga beberapa lebih besar dari jumlah target, yang kemudian membuat sisanya negatif. ( +0.5Dapat diubah ke konstanta yang berbeda untuk mengubah algoritma, tetapi tampaknya saya sudah mencapai yang optimal di sini - baik 0,4 dan 0,6 memberikan hasil yang lebih buruk.)

Untuk membuat nilai negatif negatif (dan selain itu memiliki struktur yang sama dengan yang positif, kami meneruskan operator signke fungsi rekursif kami p- baik itu "+"atau "-". Kita dapat menggunakannya untuk joiner dalam kasus sepele (yaitu n <9) juga adapun sisanya jika positif, dan gunakan tanda sebaliknya untuk sisanya jika negatif.

The proofmenangani fungsi awal tanda (dengan kasus khusus untuk 0), pfungsi melakukan pekerjaan yang sebenarnya, dengan rekursi.

Versi ketiga, untuk Ceylon 1.2

import ceylon.language { S=String, I=Integer,e=expand }

// output a base-proof Ceylon expression for an integer
// (i.e. using only 0 and 1 as digits).
//
// Question: http://codegolf.stackexchange.com/q/58084/2338
// My Answer:  http://codegolf.stackexchange.com/a/58122/2338
//
// The goal is to produce an expression as short as possible, with
// the code staying under 512 bytes in length.
//
// This approach is to represent a positive integer as a square
// of a positive integer plus some remainder (where the remainder
// can be negative), and for negative integers replace the + on the
// outer level by -.

S q(I n) =>
        n == 0 then "0"
        else (n < 0 then "-" + p(-n, "-")
            else p(n, "+"));

// cache for values of p
variable Map<[I, S],S> c = map { };

// Transforms a positive number into a base-proof term, using
// the given sign for the summation on the outer level.
S p(I n, S s) {
    S v =
    // look into the cache
            c[[n, s]] else (
        // hard-code small numbers
        n < 8 then s.join([1].repeat(n)))
            else
    // do the complicated stuff
    (let (a = "+-".replace(s,""))
            e(e {
                    for (x in 2..8) // try these exponents
                        let (l = (n ^ (1.0 / x)).integer) // \[ sqrt[exp]{n} \] in LaTeX
                            { for (r in l:2) // lowerRoot, lowerRoot + 1
                                    if (r > 1)
                                        let (w = r ^ x)
                                            { if (w-n < n) // avoid recursion to larger or same number
                                                    // format the string as  r^x + (n-w)
                                                    "(" + p(r, "+") + ")^(" + p(x, "+") + ")" +
                                                            (w < n then s + p(n - w, s)
                                                                else (n < w then a + p(w - n, a)
                                                                    else ""))
                                            } } })
            // and now find the shortest formatted string
                .reduce<S>((x, y) => x.size < y.size then x else y))
    // this should never happen, but we can't tell the compiler
    // that at least some of the iterables are non-empty due to the if clause.
            else "";

    // this builds a new cache in each step – quite wasteful,
    // as this also happens when the value was found in the cache,
    // but we don't have more characters remaining.
    //// c = map { [n, s] -> v, *c };
    ///better way:
     c = [n,s] in c then c else map{[n,s]->v, *c}; 
    return v;
}

Versi golf (yaitu komentar dan spasi kosong dihapus) diposting di bagian atas, tepatnya 509 byte kode.

Ini menggunakan prinsip dasar yang sama dengan versi kedua, tetapi alih-alih hanya kuadrat, ia juga mencoba menggunakan kekuatan angka yang lebih tinggi (mencoba eksponen dari 2 hingga 8), dan menggunakan hasil terpendek. Itu juga cache hasil, karena kalau tidak, ini akan sangat lambat untuk nomor yang lebih besar dengan banyak panggilan rekursif.

Mencetak:

Total positive: 36622
Average positive: 36.622
Total negative: 37623
Average negative: 37.58541458541458
With bonus:33.826873126873124
Overall score: 35.22443656343656

Konstruksi lekukan besar di tengah adalah tiga pemahaman yang tersusun berulang, dua batin di dalam ekspresi let. Ini kemudian diuji menggunakan fungsi memperluas dua kali, dan reducefungsi menemukan yang terpendek dari string itu.

Saya telah mengajukan permintaan fitur untuk dapat melakukan ini dalam satu pemahaman.

Di dalam pemahaman, kita sedang membangun string dari root r, eksponen xdan sisanya ( n-watau w-n).

The letekspresi dan mapfungsi baru di Ceylon 1.2. mapbisa digantikan oleh HashMap(yang akan membutuhkan lebih banyak karakter untuk impor, meskipun mungkin akan lebih cepat, karena saya tidak akan membuat peta baru untuk setiap entri baru). The letekspresi seperti let (w = r ^ x)harus diganti dengan menggunakan ifklausa seperti if(exists w = true then r ^ x)(dan kemudian aku tidak akan diperlukan dua expandpanggilan baik), tapi ini masih akan sedikit lebih lama, tidak pas dalam 511 byte diperbolehkan.

Di sini sampel keluaran sesuai dengan yang dipilih di atas, semuanya kecuali jumlah yang sangat kecil lebih pendek:

   27:  15: (1+1+1)^(1+1+1)
   28:  17: (1+1+1)^(1+1+1)+1
   29:  19: (1+1+1)^(1+1+1)+1+1
   30:  21: (1+1)^(1+1+1+1+1)-1-1
   31:  19: (1+1)^(1+1+1+1+1)-1
   32:  17: (1+1)^(1+1+1+1+1)
   33:  19: (1+1)^(1+1+1+1+1)+1
   34:  21: (1+1)^(1+1+1+1+1)+1+1

  -27:  16: -(1+1+1)^(1+1+1)
  -28:  18: -(1+1+1)^(1+1+1)-1
  -29:  20: -(1+1+1)^(1+1+1)-1-1
  -30:  22: -(1+1)^(1+1+1+1+1)+1+1
  -31:  20: -(1+1)^(1+1+1+1+1)+1
  -32:  18: -(1+1)^(1+1+1+1+1)
  -33:  20: -(1+1)^(1+1+1+1+1)-1
  -34:  22: -(1+1)^(1+1+1+1+1)-1-1

  993:  39: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1-1-1
  994:  37: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1-1
  995:  35: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1-1
  996:  33: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1-1
  997:  31: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1-1
  998:  29: ((1+1+1)^(1+1)+1)^(1+1+1)-1-1
  999:  27: ((1+1+1)^(1+1)+1)^(1+1+1)-1
 1000:  25: ((1+1+1)^(1+1)+1)^(1+1+1)

 -993:  40: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1+1+1
 -994:  38: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1+1
 -995:  36: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1+1
 -996:  34: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1+1
 -997:  32: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1+1
 -998:  30: -((1+1+1)^(1+1)+1)^(1+1+1)+1+1
 -999:  28: -((1+1+1)^(1+1)+1)^(1+1+1)+1
-1000:  26: -((1+1+1)^(1+1)+1)^(1+1+1)

    1:   1: 1
    2:   3: 1+1
    3:   5: 1+1+1
    4:   7: 1+1+1+1
    5:   9: 1+1+1+1+1
    6:  11: 1+1+1+1+1+1
    7:  13: 1+1+1+1+1+1+1
    8:  13: (1+1)^(1+1+1)
    9:  13: (1+1+1)^(1+1)
   10:  15: (1+1+1)^(1+1)+1

    0:   1: 0
   -1:   2: -1
   -2:   4: -1-1
   -3:   6: -1-1-1
   -4:   8: -1-1-1-1
   -5:  10: -1-1-1-1-1
   -6:  12: -1-1-1-1-1-1
   -7:  14: -1-1-1-1-1-1-1
   -8:  14: -(1+1)^(1+1+1)
   -9:  14: -(1+1+1)^(1+1)
  -10:  16: -(1+1+1)^(1+1)-1

Sebagai contoh, sekarang kita memiliki 1000 = (3 ^ 2 + 1) ^ 3, bukan 1000 = (6 ^ 2-4) ^ 2-5 ^ 2 + 1.

Paŭlo Ebermann
sumber
Saya salah ingat pembatasan program sebagai 256 byte ... di 512 cukup banyak lagi yang bisa dilakukan. Akan mencobanya nanti.
Paŭlo Ebermann
Nah, katanya less than 512. Sou, Anda bisa menggunakan maks. dari 511 bytes;)
mınxomaτ
Bagaimana saya belum pernah mendengar bahasa ini?!? : O Tapi serius, penjelasan luar biasa! Saya suka memahami teknik yang digunakan orang lain dalam jawaban mereka. +1
ETHproduksi
@ ETHproductions Saya juga baru membacanya sekitar dua minggu lalu di sini di situs, dan mulai menyukainya. Jadi untuk mengenalnya lebih baik, saya mencoba menjawab pertanyaan di sini menggunakan Ceylon.
Paŭlo Ebermann
2

Ruby / dc, 20.296 18.414 16.968

Pemrograman dinamis! Menentukan daftar fungsi yang, diberikan instruksi dc, mengembalikan ekspresi baru dan nilai numerik ekspresi itu. Kemudian, dimulai dengan 1prefined, ia membangun daftar semua nilai yang dapat dijangkau hingga dan termasuk nilai yang diinginkan.

edit:

Menambahkan fungsi untuk n-1 dan membuatnya menjalankan algoritma melalui beberapa lintasan. Tampaknya perlu 7 operan untuk menstabilkan. Harus mempersingkat beberapa nama variabel agar tetap dalam 512 byte.

edit 2:

Menambahkan fungsi untuk n (n-1) , n (n + 1) dan n ^ 3 saat saya masih di sana. Memperpendek kode lagi, mendarat tepat 512 byte.

N = gets.to_i

fns = [
  ->(n,s){[n-1,   s+'1-']},
  ->(n,s){[n+1,   s+'1+']},
  ->(n,s){[n*2,   s+'d+']},
  ->(n,s){[n*3,   s+'dd++']},
  ->(n,s){[n*~-n, s+'d1-*']},
  ->(n,s){[n*n,   s+'d*']},
  ->(n,s){[n*-~n, s+'d1+*']},
  ->(n,s){[n*n*n, s+'dd**']},
]

lst = []*(N+1)
lst[0..2] = %w[0 1 1d+]

loop do
  prev = lst.dup

  (1..N).each do |n|
    fns.each do |f|
      m,s = f[n, lst[n]]
      lst[m] = s if m <= N && (lst[m].nil? || lst[m].size > s.size)
    end
  end

  break if lst == prev
end

puts lst[N]

Angka yang dihasilkan:

Keluaran seluruhnya terdiri dari lima karakter yang berbeda: 1mendorong nilai 1 pada tumpukan; dmenggandakan bagian atas tumpukan; +,, -dan * muncul dua nilai teratas dan mendorong jumlah, perbedaan, dan produknya masing-masing. Setiap ekspresi yang dihasilkan menambahkan hanya satu nilai ke stack setelah eksekusi.

   1: 1
   2: 1d+
   3: 1dd++
   4: 1d+d+
   5: 1d+d+1+
   6: 1d+dd++
   7: 1d+dd++1+
   8: 1d+dd**
   9: 1dd++d*
  10: 1d+d+1+d+
  11: 1d+d+1+d+1+
  12: 1dd++d1+*
  13: 1dd++d1+*1+
  14: 1d+dd++1+d+
  15: 1d+d+d*1-
  16: 1d+d+d*
  17: 1d+d+d*1+
  18: 1dd++d*d+
  19: 1dd++d*d+1+
  20: 1d+d+d1+*
  21: 1d+d+d1+*1+
  22: 1d+d+1+d+1+d+
  23: 1d+dd**dd++1-
  24: 1d+dd**dd++
  25: 1d+d+1+d*

...

 989: 1d+d+d*d+d1-*1-1-1-
 990: 1d+d+d*d+d1-*1-1-
 991: 1d+d+d*d+d1-*1-
 992: 1d+d+d*d+d1-*
 993: 1d+d+d*d+d1-*1+
 994: 1d+d+d*d+d1-*1+1+
 995: 1d+d+d*d+d1-*1+1+1+
 996: 1d+d+1+dd**d+1-d+d+
 997: 1d+d+1+d+dd**1-1-1-
 998: 1d+d+1+d+dd**1-1-
 999: 1d+d+1+d+dd**1-
1000: 1d+d+1+d+dd**
daniero
sumber
1
Cukup bagus, mengalahkan semuanya kecuali kode mesin Z80 sejauh ini (bahkan Dennis 'CJam!). Apakah Anda pikir Anda dapat menambahkan -operator sambil tetap dalam hitungan byte?
ETHproduksi
@ ETHproductions Bagaimana? ;) Seharusnya tidak sulit untuk menambahkan angka negatif sekarang juga.
daniero
0

Python 2.6, 78.069 - 66.265 poin

Menyerahkan jawaban saya untuk apa nilainya (tidak banyak dalam kasus ini ... tapi jelas menunjukkan bahwa untuk tantangan ini tidak cukup hanya dengan memikirkan menyusun output sebagai jumlah nilai bit-shifted; ketika diperhitungkan bahwa tidak ada digit di luar 0 atau 1 dapat muncul di output). Saya mungkin akan kembali lagi nanti dengan cara yang berbeda untuk menghasilkan output.

Kode itu sendiri tidak terlalu panjang (176 karakter):

def f(a):return'+'.join(('(1<<%s)'%['0','+'.join('1'*x)][x>0]).replace('(1<<0)','1')for x in[i for i,e in enumerate(bin(a)[::-1][:-2])if int(e)])
print"".join(f(int(input())))

Ini menghasilkan output yang benar tetapi verbose:

17
1+(1<<1+1+1+1)

800
(1<<1+1+1+1+1)+(1<<1+1+1+1+1+1+1+1)+(1<<1+1+1+1+1+1+1+1+1)

Cuplikan yang menghitung skor:

def f(a):return'+'.join(('(1<<%s)'%['0','+'.join('1'*x)][x>0]).replace('(1<<0)','1')for x in[i for i,e in enumerate(bin(a)[::-1][:-2])if int(e)])
print sum(len("".join(f(i)))for i in range(1000))
ChristopheD
sumber