Produrre un'espressione a prova di base


21

sfondo

In alcuni possibili futuri, il mondo convertirà i loro sistemi numerici da decimali (base 10 o b10) in qualche altra base (binaria b2, ottale b8, esadecimale b16o persino unaria b1, nel qual caso siamo fregati!). Pertanto, in preparazione a questo possibile evento che sta cambiando il mondo, decidi di provare tutti i tuoi programmi. Questo può essere fatto utilizzando solo singolari 0s e 1s in collaborazione con gli operatori di sostituire le costanti numero esistente.

Tuttavia, c'è solo un problema: hai un sacco di programmi da cambiare e convertire manualmente ogni numero in un'espressione richiederebbe settimane! Pertanto, decidi di scrivere un programma (o una funzione) per decidere per te quale espressione dovrebbe sostituire ciascun numero.

Ingresso

L'input sarà un numero intero positivo. Il tuo codice deve essere in grado di gestire qualsiasi numero intero fino a 1000.

(Se il codice supporta decimali e / o input negativi, vedere Punteggio di seguito).

Produzione

Il codice deve generare un'espressione che valuta l'input in almeno una lingua. Questa può essere qualsiasi lingua; non deve essere lo stesso in cui è scritto il tuo programma o funzione. Inoltre, questa espressione non deve necessariamente essere un programma o una funzione completi.

Per chiarezza, l'output può contenere una di queste operazioni:

  • incremento / decremento
  • aggiungi / somma
  • sottrai / annulla
  • moltiplicare / raddoppiare (solo se non coinvolge direttamente il numero 2!)
  • divide / modulo
  • esponenti / logaritmi
  • square / sqrt (di nuovo, solo se questi non coinvolgono direttamente il numero 2!)
  • operazioni a bit (bOR, bAND, bNOT, bXOR, bit-shift)
  • impostazione / acquisizione di variabili
  • manipolazione dello stack

Si può non usare eval()o qualsiasi funzioni simili in uscita. Non è inoltre possibile utilizzare nell'output funzioni che eseguono azioni diverse da quelle sopra menzionate.

Oh, e un'altra cosa: poiché vogliamo che l'output sia valido in quante più basi possibili, le uniche costanti numeriche che può contenere sono 0e 1. Numeri come 10(dieci) non sono consentiti, a meno che la lingua non lo interpreti come a 1e a 0. Non è neppure permesso usare stringhe per contenere numeri, così come usare caratteri come CJam A- K(che rappresentano 10- 20).

Casi test

(Tutti gli output sono in JavaScript, ma potrebbero funzionare in altre lingue.)

Ingresso 1:

2

Possibile uscita 1:

1+1

Ingresso 2:

13

Possibile uscita 2:

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

Ingresso 3:

60

Possibile uscita 3:

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

Ingresso 4:

777

Possibile uscita 4:

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

Ingresso 5:

1000

Possibile uscita 5:

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

punteggio

L'obiettivo di questa sfida è abbreviare il più possibile l'output del codice. Il tuo punteggio verrà calcolato in questo modo:

  • Punteggio di base: conteggio dei byte medi di tutte le uscite per numeri interi da 1 a 1000.

  • Punteggio decimale: se il codice supporta almeno 3 cifre decimali, si tratta del conteggio dei byte medi di tutte le uscite della sequenza di numeri che iniziano 0.001e terminano a 1000, aumentando di 1.001volta in volta. 0.001, 1.002, 2.003...998.999, 1000.000Quindi prendi il 50% di sconto su questo punteggio.

  • Punteggio negativo: se il tuo codice supporta numeri negativi e zero, questo è il conteggio byte medio delle uscite di tutti i numeri interi da -1000a 0. Quindi prendi il 10% di sconto su questo punteggio.

(Il modo più semplice per calcolare questi sarebbe probabilmente un ciclo con il tuo programma / funzione all'interno.)

Il tuo punteggio finale è la media di qualunque delle formule sopra riportate.

Se l'output non è deterministico (ovvero in qualche modo casuale; più corse con lo stesso input producono più uscite uniche), il punteggio per ciascun input è determinato dall'output più grande su dieci corse sulla mia CPU.

Inoltre, poiché non sai quanto saranno preziosi i dati del computer in futuro, il conteggio dei byte del codice del generatore deve essere inferiore a 512 byte.

Il punteggio più basso in due settimane (il 30 settembre) sarà dichiarato vincitore. Congratulazioni al tuo vincitore, @ThomasKwa !


Classifica

Per assicurarti che la tua risposta venga visualizzata correttamente, ti preghiamo di avviarla con questa intestazione:

# Language name/Other language name, X points

Dov'è Xil punteggio della tua risposta. Esempio:

# CJam/Pyth, 25.38 points

Se avete domande o suggerimenti, per favore fatemi sapere. In bocca al lupo!


Posso utilizzare le variabili che contengono 0o 1per impostazione predefinita?
Dennis,

@Dennis Non vedo alcun problema, quindi vai avanti!
ETHproductions

Suppongo di non poter effettuare la conversione di base tra base 2 e base predefinita.
Blu,

@muddyfish No, nessuna conversione di base consentita nell'output.
ETHproductions

Suppongo che non ci sia permesso usare qualcosa del genere Integer.parseInt("1000", 1+1+1+1+1+1+1+1+1+1)? Sono abbastanza sicuro che parseIntusa solo le operazioni consentite ;-)
Paŭlo Ebermann,

Risposte:


10

Codice macchina 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: numeri negativi.

Presuppone che hlinizialmente la coppia di registri contenga 0 e restituisca il risultato hl.

Vengono utilizzate solo queste tre istruzioni:

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

Usiamo una piccola modifica della rappresentazione binaria bilanciata di peso minimo BBR2 . Poiché BBR2 minimizza il peso (numero di cifre diverse da zero), ma vogliamo minimizzare il peso più il numero di spostamenti di bit, cambiamo una costante nell'algoritmo da 3/2a 5/3.

Per calcolare il punteggio e verificare, utilizzare questo codice:

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

Esempio di output:

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

O in assemblea:

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

Altri programmi di esempio:

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

Possibili ottimizzazioni: le regole OP che le istruzioni inc he dec h, che modificano direttamente il byte superiore di hl, sono illegali, ma sla he sono prive di documenti sl1 h(gli spostamenti di bit a sinistra di 1 su htale spostamento in a 0e 1rispettivamente) sono consentiti. sla he sl1 hsono due byte ciascuno, ma a volte possono abbreviare l'output.


Molto bello, il più basso finora! Immagino che questo sia un esempio in cui il codice macchina puro è utile. ;)
ETHproductions,

2
+1 questo è probabilmente imbattibile. Anche per il genio dell'uso del codice macchina (su una cpu con un set di istruzioni in gran parte a 8 bit e alcuni registri a 16 bit.)
Level River St

È strano come si +traduca dec. Continuo a leggere gli esempi negativi sbagliati.
ETHproductions

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=

Non si applicano bonus.

Provalo online: esempio di esecuzione | calcolatrice del punteggio | verifica

L'esempio funziona

   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<

La mia parola, è stata veloce! Tuttavia, i collegamenti non funzionano in Firefox.
ETHproductions

Dato che questo non è un codice golf, ho sostituito ciascuno %con un'espressione più lunga. I collegamenti dovrebbero funzionare ora.
Dennis,

L'ingresso 34 dà 1. Su quale ingresso funziona meglio
Kishan Kumar

2
@KishanKumar La verifica verifica tutti i 1000 possibili input. L'output 1 indica che il confronto ha avuto esito positivo.
Dennis,

Potresti aggiungere alcuni output di esempio?
Paŭlo Ebermann,

3

ß / BrainFuck, 34.201 punti

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

Se qualcuno è interessato, aggiungerò una spiegazione. L'output BF è già abbastanza ottimizzato, ma immagino di poter utilizzare i restanti 318 B di codice ß per implementare

  • un'ottimizzazione a ciclo continuo,
  • più scorciatoie di overflow a 8 bit,
  • rimozione delle collisioni dell'operatore .

Campioni:

In esecuzione in Windows:

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

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

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

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

In esecuzione in Linux:

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

Convalida nell'interprete BF online .

I punteggi:

  1. Media Base = 37.495.
  2. Media decimale = 60.959 * 0.5 = ~30.48.
  3. Media negativa = 38.4765234765235 * 0.9 = ~34.629
  4. Media di quanto sopra, punteggio finale = (37.495 + 30.48 + 34.629)/3 = 34.201.

1
Mi piace sempre vedere le nuove lingue create dalla gente. :) Grazie per la ripartizione del punteggio! Vorrei mettere più di un bonus sulla parte decimale, quindi ho modificato la detrazione dal 40% al 50%.
ETHproductions

@ETHproductions Sì, proverò a creare un interprete online per questo. Ci sono circa 435 operatori altamente astratti, altri 9,9k possono essere definiti ;-). Ho corretto il calcolo (si spera).
mınxomaτ,

3

Ruby / Ruby, 29.77885

31.873 * 0.9 (negativo) 30.872 (positivo).

La strategia di base è la rappresentazione simmetrica di base 3 ("ternario bilanciato"), ovvero quando le cifre sono -1,0,1invece di0,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

Ecco l'output da 0 a 40 prima della pulizia

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

E dopo la pulizia

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

Credo che si chiami "ternario equilibrato".
lirtosiast,

@ThomasKwa modificato, grazie
Level River St

3

Ceylon / Ceylon, 49,86 40,95 punti

La terza versione utilizza Ceylon 1.2 per il generatore e 509 byte di codice:

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

Si scende a 35.22 punti, ma non lo inserirò nella linea del titolo perché Celyon 1.2 è stato pubblicato solo il 29 ottobre. Non credo che sarei in grado di implementare questo algoritmo in Ceylon 1.1 in queste dimensioni.). Maggiori dettagli laggiù, qui descriverò la seconda versione. (La prima versione può essere vista nella cronologia: supportava solo numeri positivi, ma si adattava a 256 byte.)

Seconda versione

Ora la seconda versione, che supporta numeri interi negativi (e 0), e in genere crea un output un po 'più breve utilizzando in aggiunta -. (Questa versione utilizza effettivamente la lunghezza consentita, la prima ha tentato di rimanere sotto i 256 byte anziché 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 ""));
}

Il codice ha una lunghezza di 487, quindi c'è ancora spazio per ulteriori ottimizzazioni in seguito. (Ci sono anche molte riserve in forma di spazi bianchi e nomi di variabili lunghe.)

Il punteggio:

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

Alcuni output di esempio:

   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

Come puoi vedere, quelli negativi sono sempre un byte (il primo -) più lunghi di quelli positivi corrispondenti.

L'idea di base è la stessa del programma precedente: trovare un quadrato vicino al nostro numero target e rappresentare ricorsivamente la sua radice e il resto. Ma ora permettiamo che il nostro quadrato sia anche un po 'più grande del numero target, il che rende il resto negativo. (È +0.5possibile modificare una costante diversa per modificare l'algoritmo, ma sembra che qui abbia già raggiunto l'ottimale - sia 0.4 che 0.6 danno risultati peggiori.)

Per rendere negativi i valori negativi (e altrimenti avere la stessa struttura di quelli positivi, passiamo l'operatore signalla nostra funzione ricorsiva p- ovvero o "+"oppure "-". Possiamo usarlo anche per il joiner in casi banali (cioè n <9) come per il resto se è positivo e usa il segno opposto per il resto se è negativo.

La prooffunzione gestisce il segno iniziale (con un caso speciale per 0), la pfunzione esegue il lavoro effettivo, con ricorsione.

Terza versione, per 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;
}

La versione golfata (ovvero commenti e spazi bianchi rimossi) è pubblicata in alto, esattamente a 509 byte di codice.

Questo utilizza lo stesso principio di base della seconda versione, ma invece di solo quadrati, cerca anche di usare potenze numeriche più elevate (tentando esponenti da 2 a 8) e usa il risultato più breve. Inoltre memorizza nella cache i risultati, altrimenti questo sarebbe inaccettabilmente lento per numeri più grandi con molte chiamate ricorsive.

punteggio:

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

Il grande costrutto rientrato nel mezzo sono tre comprimibili comprensioni comprensibili, i due interni all'interno di un'espressione let. Questi non vengono quindi rilevati utilizzando la funzione di espansione due volte e la reducefunzione trova la più breve di quelle stringhe.

Ho presentato una richiesta di funzionalità per poterlo fare in una sola comprensione.

All'interno della comprensione, stiamo costruendo una stringa dalla radice r, dall'esponente xe dal resto ( n-wo w-n).

L' letespressione e la mapfunzione sono nuove in Ceylon 1.2. mapavrebbe potuto essere sostituito da HashMap(che avrebbe richiesto più caratteri per l'importazione, anche se probabilmente sarebbe ancora più veloce, dato che non avrei creato la mappa nuova per ogni nuova voce). Le letespressioni come let (w = r ^ x)avrebbero potuto essere sostituite usando una ifclausola like if(exists w = true then r ^ x)(e quindi non avrei nemmeno avuto bisogno delle due expandchiamate), ma questo sarebbe comunque un po 'più lungo, non rientrando nei 511 byte consentiti.

Qui gli output di esempio corrispondenti a quelli selezionati sopra, tutti tranne i numeri veramente piccoli sono più brevi:

   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

Ad esempio, ora abbiamo 1000 = (3 ^ 2 + 1) ^ 3, anziché 1000 = (6 ^ 2-4) ^ 2-5 ^ 2 + 1.


Ho erroneamente ricordato la limitazione del programma come 256 byte ... in 512 si può fare molto di più. Ci proverò più tardi.
Paŭlo Ebermann,

No, dice less than 512. Puoi usare un max. di 511 byte;)
mınxomaτ,

Come non ho mai sentito parlare di questa lingua?!? : O Ma sul serio, eccellente spiegazione! Mi piace capire le tecniche che gli altri usano nelle loro risposte. +1
Produzioni ETH il

@ETHproductions Ne ho anche letto solo circa due settimane fa qui sul sito e ho iniziato a piacermi. Quindi, per conoscerlo meglio, provo a rispondere alle domande qui usando Ceylon.
Paŭlo Ebermann,

2

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

Programmazione dinamica! Definisce un elenco di funzioni che, dati un'istruzione dc, restituiscono una nuova espressione e il valore numerico di quella espressione. Quindi, a partire da 1predefinito, crea un elenco di tutti i valori raggiungibili fino al valore desiderato incluso.

modificare:

Aggiunta una funzione per n-1 e fatto funzionare l'algoritmo attraverso più passaggi. Sembra aver bisogno di 7 passaggi per stabilizzarsi. Ho dovuto abbreviare alcuni nomi di variabili per rimanere entro 512 byte.

modifica 2:

Aggiunte funzioni per n (n-1) , n (n + 1) e n ^ 3 mentre ero lì. Abbreviato ulteriormente il codice, atterrando esattamente a 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]

Numeri generati:

L'output è composto interamente da cinque caratteri diversi: 1inserisce il valore 1 nello stack; dduplica la parte superiore della pila; +, -e visualizza * i due valori principali e invia rispettivamente la loro somma, differenza e prodotto. Ogni espressione generata aggiunge un solo valore allo stack dopo l'esecuzione.

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

1
Abbastanza buono, battendo tutto tranne il codice macchina z80 finora (anche Dennis 'CJam!). Pensi che potresti essere in grado di aggiungere un -operatore rimanendo nel conteggio dei byte?
ETHproductions

@ETHproductions Come va? ;) Non dovrebbe essere difficile aggiungere numeri negativi ora.
daniero,

0

Python 2.6, 78.069 - 66.265 punti

Inviare la mia risposta per ciò che vale (non molto in questo caso ... ma dimostrando chiaramente che per questa sfida non è sufficiente pensare semplicemente a comporre l'output come una somma di valori spostati in bit; se si considera che nessuna cifra al di fuori di 0 o 1 potrebbe apparire nell'output). Potrei tornare più tardi con un modo diverso di generare output.

Il codice stesso non è troppo lungo (176 caratteri):

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

Genera un output corretto ma dettagliato:

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)

Snippet che calcola il punteggio:

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.