Wyprowadzanie wyrażenia niepoprawnego dla bazy

21

tło

W niektórych możliwych przyszłościach świat przekształci swój system liczbowy z dziesiętnego (podstawa 10 lub b10) na jakąś inną bazę (dwójkową b2, ósemkową b8, szesnastkową b16, a nawet jednoargumentową b1, w którym to przypadku jesteśmy zepsute!). Tak więc, przygotowując się do tego możliwego wydarzenia zmieniającego świat, zdecydujesz się zabezpieczyć wszystkie swoje programy. Można to zrobić, używając tylko liczby pojedynczej 0si 1w połączeniu z operatorami w celu zastąpienia istniejących stałych liczbowych.

Jest jednak tylko jeden problem: masz mnóstwo programów do zmiany, a ręczne przekształcenie każdej liczby w wyrażenie zajęłoby tygodnie! Dlatego decydujesz się napisać program (lub funkcję), aby zdecydować, które wyrażenie powinno zastąpić każdą liczbę.

Wkład

Wejście będzie dodatnią liczbą całkowitą. Twój kod musi być w stanie obsłużyć dowolną liczbę całkowitą do 1000.

(Jeśli Twój kod obsługuje wartości dziesiętne i / lub ujemne, patrz punktacja poniżej.)

Wydajność

Twój kod musi wypisywać wyrażenie, które ocenia dane wejściowe w co najmniej jednym języku. Może to być dowolny język; to nie musi być ten sam, w którym zapisany jest Twój program lub funkcja. Ponadto, to wyrażenie nie musi być pełnym programem lub funkcją.

Dla jasności dane wyjściowe mogą zawierać dowolne z następujących operacji:

  • przyrost / spadek
  • dodaj / suma
  • odejmuj / neguj
  • pomnożyć / podwójnie (tylko jeśli nie dotyczy bezpośrednio liczby 2!)
  • divide / modulo
  • wykładniki / logarytmy
  • kwadrat / sqrt (ponownie, tylko jeśli nie dotyczą one bezpośrednio liczby 2!)
  • operacje bitowe (bOR, bAND, bNOT, bXOR, zmiany bitów)
  • ustawianie / uzyskiwanie zmiennych
  • manipulacja stosami

Być może nie używać eval()lub inne podobne funkcje w wyjściu. Nie możesz również używać w danych wyjściowych żadnych funkcji wykonujących działania inne niż wymienione powyżej.

Aha, i jeszcze jedno: ponieważ chcemy, aby dane wyjściowe były poprawne w jak największej liczbie zasad, jedynymi stałymi liczbowymi, które może zawierać, są: 0 i 1. Liczby takie jak 10(dziesięć) są niedozwolone, chyba że język interpretuje je jako a 1i a 0. Używanie ciągów zawierających liczby również nie jest dozwolone, podobnie jak używanie znaków takich jak CJam A- K(które reprezentują 10- 20).

Przypadki testowe

(Wszystkie dane wyjściowe są w języku JavaScript, ale mogą działać w innych językach).

Wejście 1:

2

Możliwe wyjście 1:

1+1

Wejście 2:

13

Możliwe wyjście 2:

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

Wejście 3:

60

Możliwe wyjście 3:

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

Wejście 4:

777

Możliwe wyjście 4:

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

Wejście 5:

1000

Możliwe wyjście 5:

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

Punktacja

Celem tego wyzwania jest maksymalne skrócenie danych wyjściowych kodu. Twój wynik zostanie obliczony w następujący sposób:

  • Wynik podstawowy: średnia liczba bajtów wszystkich wyjść dla liczb całkowitych od 1 do 1000.

  • Wynik dziesiętny: jeśli kod obsługuje co najmniej 3 miejsca dziesiętne, jest to średnia liczba bajtów wszystkich wyników sekwencji liczb rozpoczynających się 0.001i kończących o 1000, zwiększana o1.001 każdym razem. 0.001, 1.002, 2.003...998.999, 1000.000Następnie weź 50% zniżki na ten wynik.

  • Wynik ujemny: jeśli kod obsługuje liczby ujemne i zero, jest to średnia liczba bajtów wyjść wszystkich liczb całkowitych z-1000 do 0. Następnie weź 10% zniżki na ten wynik.

(Najłatwiejszym sposobem ich obliczenia jest prawdopodobnie pętla z programem / funkcją w środku).

Twój końcowy wynik jest średnią z którejkolwiek z powyższych formuł.

Jeśli dane wyjściowe nie są deterministyczne (tj. Nieco losowe; wiele przebiegów z tym samym wejściem daje wiele unikalnych wyników), to wynik dla każdego wejścia jest określany przez największe wyjście z dziesięciu przebiegów na moim CPU.

Ponadto, ponieważ nie wiesz, jak cenne będą dane komputerowe w przyszłości, liczba bajtów kodu generatora musi być mniejsza niż 512 bajtów.

Najniższy wynik od dwóch tygodni (30 września) zostanie ogłoszony zwycięzcą. Gratulacje dla zwycięzcy, @ThomasKwa !


Tabela liderów

Aby upewnić się, że twoja odpowiedź wyświetla się poprawnie, zacznij od tego nagłówka:

# Language name/Other language name, X points

Gdzie Xjest wynik twojej odpowiedzi. Przykład:

# CJam/Pyth, 25.38 points

Jeśli masz jakieś pytania lub sugestie, daj mi znać. Powodzenia!

ETHprodukcje
źródło
Czy mogę używać zmiennych, które przechowują 0lub 1domyślnie?
Dennis,
@Dennis Nie widzę z tym żadnego problemu, więc śmiało!
ETHprodukcje
Zakładam, że nie mogę wykonać konwersji bazy między bazą 2 a bazą domyślną.
Niebieski,
@muddyfish Nie, nie ma konwersji bazowej na wyjściu.
ETHprodukcje
Chyba też nie wolno nam używać czegoś takiego Integer.parseInt("1000", 1+1+1+1+1+1+1+1+1+1)? Jestem pewien, że parseIntużywa tylko dozwolonych operacji ;-)
Paŭlo Ebermann

Odpowiedzi:

10

Kod maszynowy 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]

Bonusy: liczby ujemne.

Zakłada, że hlpara rejestrów początkowo ma wartość 0 i zwraca wynik hl.

Używane są tylko te trzy instrukcje:

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

Używamy niewielkiej modyfikacji zrównoważonej reprezentacji binarnej BBR2 o minimalnej wadze . Ponieważ BBR2 minimalizuje wagę (liczbę niezerowych cyfr), ale chcemy zminimalizować wagę plus liczbę przesunięć bitów, zmieniamy stałą w algorytmie z 3/2na 5/3.

Aby obliczyć wynik i zweryfikować, użyj tego kodu:

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)]))

Przykładowe dane wyjściowe:

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

Lub w montażu:

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

Więcej przykładowych programów:

-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  #))#

Możliwe optymalizacje: OP określa, że instrukcje inc hi dec h, które bezpośrednio zmieniają górny bajt hl, są niedozwolone, ale sla hnieudokumentowane sl1 h(przesunięcie lewego bitu o 1 odpowiednio dla htego przesunięcia w 0ai 1) jest dozwolone. sla hi sl1 hmają po dwa bajty, ale czasem mogą skrócić wynik.

lirtosiast
źródło
Bardzo fajnie, najniższa jak dotąd! Wydaje mi się, że jest to jeden przykład, w którym przydaje się czysty kod maszynowy. ;)
ETHprodukcje
2
+1 to prawdopodobnie nie do pobicia. Również za geniusz używania kodu maszynowego (na procesorze z zestawem instrukcji w większości 8-bitowym i około 16-bitowymi rejestrami.)
Level River St.
To dziwne, jak się +tłumaczy dec. Ciągle czytam negatywne przykłady.
ETHprodukcje
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=

Nie obowiązują żadne bonusy.

Wypróbuj online: uruchomienie próbne | kalkulator wyników |weryfikacja

Przykład działa

   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
źródło
Moje słowo, to było szybkie! Linki nie działają jednak w przeglądarce Firefox.
ETHprodukcje
Ponieważ nie jest to golf golfowy, każdy %z nich zastąpiłem dłuższym wyrażeniem. Linki powinny teraz działać.
Dennis,
Wejście 34 daje 1. Na którym wejściu działa lepiej
Kishan Kumar,
2
@KishanKumar Weryfikacja testuje wszystkie 1000 możliwych danych wejściowych. Wyjście 1 wskazuje, że porównanie zakończyło się powodzeniem.
Dennis,
Czy możesz dodać jakieś przykładowe dane wyjściowe?
Paŭlo Ebermann
3

ß / BrainFuck, 34.201 punktów

ß źródło (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)

Jeśli ktoś jest zainteresowany, dodam wyjaśnienie. Wyjście BF jest już dość zoptymalizowane, ale wydaje mi się, że mógłbym wykorzystać pozostałe 318B kodu ß do implementacji

  • optymalizacja zagnieżdżania w pętli,
  • więcej 8-bitowych skrótów przelewowych,
  • usuwanie kolizji operatora .

Próbki:

Uruchamianie w systemie Windows:

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

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

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

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

Uruchamianie w systemie Linux:

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

Zatwierdź w internetowym tłumaczu BF .

Wyniki:

  1. Średnia podstawowa = 37.495.
  2. Średnia dziesiętna = 60.959 * 0.5 = ~30.48.
  3. Średnia ujemna = 38.4765234765235 * 0.9 = ~34.629
  4. Średnia z powyższych, wynik końcowy = (37.495 + 30.48 + 34.629)/3 = 34.201.
mınxomaτ
źródło
1
Zawsze lubię widzieć nowe języki, które ludzie stworzyli. :) Dzięki za podział wyników! Chciałbym dodać więcej premii do części dziesiętnej, więc zmieniłem odliczenie z 40% na 50%.
ETHprodukcje
@ETHproductions Tak, spróbuję skonfigurować do tego celu tłumacza internetowego. Istnieje około 435 wysoce abstrakcyjnych operatorów, można zdefiniować dodatkowe 9,9k ;-). Poprawiłem obliczenia (mam nadzieję).
mınxomaτ
3

Ruby / Ruby, 29,77885

31,873 * 0,9 (ujemny) 30,872 (dodatni).

Podstawową strategią jest symetryczna reprezentacja podstawy 3 („zbalansowana trójskładnikowa”), tzn. Kiedy cyfry są -1,0,1zamiast0,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

Oto wynik od 0 do 40 przed czyszczeniem

(+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)

I po sprzątaniu

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
źródło
Uważam, że nazywa się to „zrównoważonym trójskładnikiem”.
lirtosiast
@ThomasKwa edytowane w, dzięki
Level River St
3

Ceylon / Ceylon, 49,86 40,95 punktów

Trzecia wersja wykorzystuje Ceylon 1.2 do generatora i 509 bajtów kodu:

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

Spada do 35,22 punktów, ale nie umieszczę tego w tytule, ponieważ Celyon 1.2 został opublikowany tylko 29 października. Nie sądzę, że byłbym w stanie zaimplementować ten algorytm na Cejlonie 1.1 w tym rozmiarze.) Więcej szczegółów na dole, tutaj opiszę drugą wersję. (Pierwsza wersja jest widoczna w historii - obsługuje tylko liczby dodatnie, ale mieści się w 256 bajtach).

Druga wersja

Teraz druga wersja, która obsługuje ujemne liczby całkowite (i 0) i generalnie generuje nieco krótszy wynik, używając dodatkowo -. (Ta wersja faktycznie używa dozwolonej długości, pierwsza próbowała pozostać poniżej 256 bajtów zamiast 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 ""));
}

Kod ma długość 487, więc jest jeszcze miejsce na późniejsze optymalizacje. (Istnieje również wiele rezerw w postaci białych znaków i długich nazw zmiennych).

Punktacja:

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

Niektóre przykładowe wyniki:

   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

Jak widać, wartości ujemne są zawsze o jeden bajt (wiodące -) dłuższe niż odpowiadające im wartości dodatnie.

Podstawowa idea jest taka sama jak w poprzednim programie: znajdź kwadrat w pobliżu naszej liczby docelowej i rekurencyjnie reprezentuj jego pierwiastek, a resztę. Ale teraz pozwalamy, aby nasz kwadrat był również trochę większy niż liczba docelowa, co powoduje, że reszta jest ujemna. ( +0.5Można zmienić na inną stałą, aby ulepszyć algorytm, ale wygląda na to, że już osiągnąłem tu optymalny - zarówno 0,4, jak i 0,6 dają gorsze wyniki.)

Aby wartości ujemne ujemny (a poza tym mają taką samą strukturę jak pozytywnymi mijamy operatora signdo naszej funkcji rekurencyjnej p- to jest albo "+"albo"-" . Możemy użyć jej dla stolarza w błahych przypadkach (tj n <9), jak również jak dla reszty, jeśli jest dodatnia, i użyj znaku przeciwnego dla reszty, jeśli jest ujemna.

Te proofuchwyty funkcyjne początkowy znak (ze szczególnym przypadku do 0), to pfunkcja ma rzeczywistej pracy, z rekursji.

Trzecia wersja, dla 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;
}

Wersja w golfa (tj. Usunięte komentarze i białe znaki) jest umieszczona na górze, dokładnie w 509 bajtach kodu.

Wykorzystuje tę samą zasadę podstawową, co druga wersja, ale zamiast zwykłych kwadratów próbuje również użyć wyższych mocy liczb (wypróbowanie wykładników od 2 do 8) i używa najkrótszego wyniku. Zapisuje również wyniki w pamięci podręcznej, ponieważ w przeciwnym razie byłoby to nie do zaakceptowania zbyt wolno dla większych numerów z wieloma rekurencyjnymi połączeniami.

Punktacja:

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

Duży wcięty konstrukt w środku to trzy zagnieżdżone iteracyjne pojęcia, dwa wewnętrzne w wyrażeniu let. Są one następnie usuwane przy użyciu funkcji rozwinięcia dwukrotnie, a reducefunkcja znajduje najkrótszy z tych ciągów.

Złożyłem prośbę o funkcję, aby móc to zrobić w jednym zrozumieniu.

Wewnątrz tego pojęcia budujemy ciąg znaków od nasady r, wykładnika xi reszty ( n-wlub w-n).

letEkspresja i mapfunkcja są nowe na Cejlonie 1.2. mapmógł zostać zastąpiony przez HashMap(co wymagałoby więcej znaków do importu, chociaż prawdopodobnie byłoby to jeszcze szybsze, ponieważ nie budowałbym mapy nowej dla każdego nowego wpisu). Do letwyrażenia jak let (w = r ^ x)mogła być zastąpiona przez zastosowanie ifklauzuli podobnego if(exists w = true then r ^ x)(i wtedy nie potrzebowałby dwóch expandpołączeń albo), ale to nadal będzie nieco dłużej, nie mieszczące się wewnątrz dozwolonych 511 bajtów.

Tutaj przykładowe dane wyjściowe odpowiadające tym wybranym powyżej, wszystkie z wyjątkiem naprawdę małych liczb są krótsze:

   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

Na przykład teraz mamy 1000 = (3 ^ 2 + 1) ^ 3, zamiast 1000 = (6 ^ 2-4) ^ 2-5 ^ 2 + 1.

Paŭlo Ebermann
źródło
Źle zapamiętałem ograniczenie programu, ponieważ 256 bajtów ... w 512 można zrobić o wiele więcej. Spróbuję później.
Paŭlo Ebermann
Nie, mówi less than 512. Możesz użyć maks. z 511 bajtów;)
mınxomaτ
Jak nigdy nie słyszałem o tym języku?!? : O Poważnie, doskonałe wyjaśnienie! Uwielbiam rozumieć techniki, których używają inni w swoich odpowiedziach. +1
ETHprodukcje
@ETHproductions Przeczytałem o tym tylko dwa tygodnie temu tutaj na stronie i zacząłem go lubić. Aby więc to lepiej poznać, staram się odpowiadać na pytania tutaj, używając Cejlonu.
Paŭlo Ebermann
2

Ruby / dc, 20,296 18,414 16,968

Programowanie dynamiczne! Definiuje listę funkcji, które po otrzymaniu instrukcji dc zwracają nowe wyrażenie i wartość liczbową tego wyrażenia. Następnie, zaczynając od 1preferencji, tworzy listę wszystkich osiągalnych wartości aż do pożądanej wartości.

edytować:

Dodano funkcję dla n-1 i zmusiła go do uruchomienia algorytmu przez wiele przejść. Wydaje się, że potrzebuje 7 przejść, aby się ustabilizować. Musiałem skrócić niektóre nazwy zmiennych, aby pozostały w obrębie 512 bajtów.

edycja 2:

Dodano funkcje dla n (n-1) , n (n + 1) i n ^ 3, gdy byłem przy tym. Skróciłem nieco kod, lądując dokładnie na 512 bajtach.

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]

Wygenerowane liczby:

Wynik składa się całkowicie z pięciu różnych znaków: 1przesuwa wartość 1 na stos; dduplikuje górę stosu; +, -i * wyświetla dwie najwyższe wartości i przesuwa odpowiednio ich sumę, różnicę i iloczyn. Każde wygenerowane wyrażenie dodaje po wykonaniu tylko jedną wartość do stosu.

   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
źródło
1
Całkiem nieźle, jak dotąd pokonując wszystko oprócz kodu maszynowego Z80 (nawet CJam Dennisa!). Czy uważasz, że możesz dodać -operatora, pozostając w liczbie bajtów?
ETHprodukcje
@ETHproductions Jak to jest? ;) Teraz też nie powinno być trudno dodawać liczby ujemne.
daniero
0

Python 2.6, 78.069 - 66.265 punktów

Przesłanie mojej odpowiedzi za to, co jest warte (w tym przypadku nie za wiele ... ale jednoznaczne wykazanie, że w przypadku tego wyzwania nie wystarczy po prostu pomyśleć o skomponowaniu wyniku jako sumy przesuniętych bitowo wartości; biorąc pod uwagę, że nie ma cyfr poza 0 lub 1 może pojawić się na wyjściu). Mogę wrócić później z innym sposobem generowania produkcji.

Sam kod nie jest zbyt długi (176 znaków):

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())))

Generuje poprawne, ale pełne dane wyjściowe:

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)

Fragment, który oblicza wynik:

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
źródło