Operatore di borsa in viaggio nel tempo


21

Storia
Molto tempo fa Bobby ha creato un portafoglio Bitcoin con 1 Satoshi (1e-8 BTC, la più piccola unità di valuta) e se ne è dimenticato. Come molti altri in seguito ha pensato "Accidenti, se solo avessi investito di più allora ...".
Non fermandosi a sognare ad occhi aperti, dedica tutto il suo tempo e denaro alla costruzione di una macchina del tempo. Trascorre la maggior parte del tempo nel suo garage, inconsapevole delle vicende mondane e delle voci che circolano su di lui. Completa il prototipo il giorno prima che l'elettricità stia per spegnersi a causa di mancati pagamenti. Alzando gli occhi dal suo banco di lavoro vede un furgone della polizia accostarsi a casa sua, sembra che i vicini ficcanaso pensino che stia gestendo un laboratorio di meth nel suo garage e abbia chiamato la polizia.
Senza tempo per eseguire i test, afferra una chiavetta USB con i dati sui tassi di cambio degli anni passati, collega il condensatore di flusso al discombobulatore quantico e si ritrova trasportato indietro nel giorno in cui ha creato il suo portafoglio

Attività
Dati i dati del tasso di cambio, scopri quanti soldi Bobby può fare. Segue una regola molto semplice: "Compra basso - vendi alto" e siccome inizia con un capitale infinitamente piccolo, supponiamo che le sue azioni non avranno alcun impatto sui tassi di cambio del futuro.

Input
Un elenco di float> 0, sia come stringa separata da un singolo carattere (newline, tab, spazio, punto e virgola, qualunque cosa tu preferisca) passato come argomento della riga di comando al programma, letto da un file di testo o STDIN o passato come parametro a una funzione. È possibile utilizzare tipi di dati numerici o matrici invece di una stringa perché in pratica è solo una stringa con parentesi.

Output
Il fattore per cui il capitale di Bobbys si è moltiplicato per la fine della negoziazione.

Esempio

Input:  0.48 0.4 0.24 0.39 0.74 1.31 1.71 2.1 2.24 2.07 2.41

Tasso di cambio: 0,48 $ / BTC, poiché sta per cadere vendiamo tutti i Bitcoin per 4,8 nanodollari. Fattore = 1 Tasso di cambio: 0,4, non fare nulla
Tasso di cambio: 0,24 $ / BTC e in aumento: converti tutti i $ in 2 Satoshi. Fattore = 1 (il valore del dollaro è ancora invariato)
Tasso di cambio: 0,39 - 2,1 $ / BTC: non fare nulla
Tasso di cambio: 2,24 $ / BTC: vendere tutto prima del calo. 44,8 nanodollari, fattore = 9,33
Tasso di cambio: 2,07 $ / BTC: acquisto 2,164 Satoshi, fattore = 9,33
Tasso di cambio: 2,41 $ / BTC: acquisto 52,15 nanodollari, fattore = 10,86

Output: 10.86

Dettagli aggiuntivi
È possibile ignorare strani casi limite come input costanti, valori zero o negativi, un solo numero di input, ecc.
Sentiti libero di generare i tuoi numeri casuali per testare o utilizzare grafici azionari reali. Ecco un input più lungo per il test (output previsto circa 321903884.638) Spiega
brevemente cosa fa il tuo codice I
grafici sono apprezzati ma non necessari


Se prendiamo i numeri tramite l'argomento della funzione, deve comunque essere una stringa o potremmo prendere direttamente un array?
Martin Ender,

@ MartinBüttner Ci ho riflettuto per un po ', sia che l'input sia una stringa, una matrice numerica o una scelta libera, ci sono sempre alcune lingue che ottengono un vantaggio. Non sembra esserci un consenso generale su questo, e scrivere due programmi, uno per un input numerico e uno per l'input di stringhe e la media di entrambi i punteggi sembra eccessivo.
DenDenDo,

Che dire dell'Infinite Improbability Drive? :)
Maniglia della porta

2
Tornando al problema, dobbiamo arrotondare i valori BTC e / o $ con una data precisione, ad ogni iterazione? Ad esempio, nel mondo reale il proprio portafoglio BTC deve essere arrotondato al Satoshi. Questo fa la differenza, perché nel tuo esempio a 2.07 puoi acquistare solo 2s (non 2.164); quindi a 2.41 i tuoi 2 ti comprano 48.2 n $ (non 52.15) quindi il fattore è 10.04 (non 10.86). A meno che tu non mantenga un portafoglio $ separato con la modifica e debba aggiungerlo nuovamente ogni volta. E i dollari? Qualcuno può oggi affermare di avere un nanodollaro? Credo che la quantità minima che si possa contenere sia 1 ¢.
Tobia,

1
@CortAmmon: stai dicendo che il trading BTC non è caotico? ;-)
Steve Jessop,

Risposte:


10

APL, 16 caratteri

{×/1⌈÷/⊃⍵,¨¯1⌽⍵}

Questa versione utilizza @Frxstrem 's più semplice algoritmo e @xnor ' s max(r,1)idea.

Presuppone anche che la serie sia complessivamente in aumento, ovvero il primo valore di bitcoin è inferiore a quello precedente. Ciò è coerente con la descrizione del problema. Per ottenere una formula più generale, è necessario eliminare la prima coppia di tariffe, aggiungendo 2 caratteri:{×/1⌈÷/⊃1↓⍵,¨¯1⌽⍵}

Esempio:

    {×/1⌈÷/⊃⍵,¨¯1⌽⍵}  0.48 0.4 0.24 0.39 0.74 1.31 1.71 2.1 2.24 2.07 2.41
10.86634461
    {×/1⌈÷/⊃⍵,¨¯1⌽⍵}  (the 1000 array from pastebin)
321903884.6

Spiegazione:

Inizia con i dati del tasso di cambio:

    A←0.48 0.4 0.24 0.39 0.74 1.31 1.71 2.1 2.24 2.07 2.41

Associa ogni numero al precedente (il primo verrà accoppiato con l'ultimo) e mettili in una matrice:

    ⎕←M←⊃A,¨¯1⌽A
0.48 2.41
0.4  0.48
0.24 0.4
0.39 0.24
0.74 0.39
1.31 0.74
1.71 1.31
2.1  1.71
2.24 2.1
2.07 2.24
2.41 2.07

Riduci ciascuna riga per divisione, mantieni quelle con rapporto> 1 e combina i rapporti per moltiplicazione. Ciò eliminerà tutti i fattori che si ripetono in una fila di tassi crescenti successivi, nonché il rapporto spurio tra il primo e l'ultimo tasso di cambio:

    ×/1⌈÷/M
10.86634461

Il tuo presupposto che dovresti sempre vendere nella prima posizione fa fallire l' input più lungo e restituisce un numero inferiore a 1 (il che è ovviamente impossibile).
Frxstrem,

@Frxstrem grazie, risolto. Ora dà lo stesso risultato della tua sceneggiatura. Sarebbe stato più utile se l'OP ci avesse fornito alcuni casi di test con risultati!
Tobia,

1
Adoro le buone soluzioni APL perché, ogni volta che le guardo, attivano il mio filtro "Questo è un file binario senza senso" e inizio a cercare un'estensione di file per capire come aprirlo.
Cort Ammon - Ripristina Monica il

@CortAmmon non è affatto infondato: APL impiega molte dozzine di operatori grafici; in superficie possono ricordare i simboli dei set di caratteri DOS a 8 bit. È anche un linguaggio molto conciso, il che significa che una linea di APL ha un'entropia di informazioni molto elevata. Queste due funzionalità si combinano per innescare la sensazione di un file binario scaricato in una finestra DOS. Ma dura solo fino a quando non impari ad apprezzare la bellezza dei simboli e della sintassi di APL.
Tobia,

6

Python, 47

f=lambda t:2>len(t)or max(t[1]/t[0],1)*f(t[1:])

Esempio eseguito sul test case .

Prendi un elenco di galleggianti. Si moltiplica ricorsivamente sul fattore profitto dai primi due elementi fino a quando rimangono meno di due elementi. Per il caso base, indica Truequale è uguale 1.

L'utilizzo popdà lo stesso numero di caratteri.

f=lambda t:2>len(t)or max(t[1]/t.pop(0),1)*f(t)

Così va dalla fine dell'elenco.

f=lambda t:2>len(t)or max(t.pop()/t[-1],1)*f(t)

Per fare un confronto, il mio codice iterativo in Python 2 è 49 caratteri, 2 caratteri più a lungo

p=c=-1
for x in input():p*=max(x/c,1);c=x
print-p

Iniziare c=-1è un hack per fare in modo che la prima "mossa" immaginaria non mostri alcun profitto. Avvio del prodotto -1anziché1 consentirci di assegnare entrambi gli elementi insieme e lo neghiamo gratuitamente prima della stampa.


Il testcase più lungo supera il limite di ricorsione predefinito di 1. f (x [: 999]) fornisce comunque il risultato corretto. Per input più lunghi potresti dividerlo in blocchi ([n:(n+1)*500 + 1] for n in range(N_elem/500) )e moltiplicare i fattori parziali
DenDenDo,

Il limite di ricorsione dipende dall'implementazione; puoi usare Stackless Python per evitarlo.
xnor

Oppure usa sys.setrecursionlimit(in CPython)
user253751 il

3

Python, 79 81 76 77 byte

f=lambda x:reduce(float.__mul__,(a/b for a,b in zip(x[1:],x[:-1]) if a>b),1.)

xè l'ingresso codificato come un elenco. La funzione restituisce il fattore.


Forse è solo la mia versione di Python, ma ho dovuto usare 1.invece che 1alla fine della funzione, altrimenti ottengo TypeError: il descrittore ' mul ' richiede un oggetto 'float' ma ha ricevuto un 'int'
Tobia

A proposito, algoritmo intelligente!
Tobia,

Non hai bisogno di quella f=parte.
wizzwizz4,

2

CJam, 33 byte

q~{X1$3$-:X*0>{\;}*}*](g\2/{~//}/

Questo può essere ulteriormente giocato a golf.

Riceve input da STDIN, come

[0.48 0.4 0.24 0.39 0.74 1.31 1.71 2.1 2.24 2.07 2.41]

e genera il fattore su STDOUT, come

10.866344605475046

Provalo online qui


1

Pyth , 18 anni

u*GeS,1ceHhHC,QtQ1

Spiegazione:

u                 reduce, G is accumulator, H iterates over sequence
 *G               multiply G by
   eS             max(               
     ,1               1,
       ceHhH            H[1]/H[0])
 C                H iterates over zip(
  ,QtQ                                Q,Q[1:])
 1                G is initialized to 1

max(H[1]/H[0],1) idea grazie a @xnor


1

C #, 333 , 313

Il mio primo tentativo. Probabilmente potrei ottimizzarlo di più, ma come ho detto il primo tentativo, quindi riusciremo a capire !.

double a(double [] b){var c=0.0;var d=1;for(int i=0;i<b.Count();i++){c=(d==1)?(((i+1)<b.Count()&&b[i+1]<=b[i]&&d==1)?((c==0)?b[i]:b[i]*c):((i+1)>=b.Count()?(c*b[i])/b[0]:c)):((i+1)<b.Count()&&b[i+1]>b[i]&&d==0)?c/b[i]:c;d=((i+1)<b.Count()&&b[i+1]<b[i]&&d==1)?0:((i+1)<b.Count()&&b[i+1]>b[i]&&d==0)?1:d;}return c;}

Ingresso

0.48, 0.4, 0.24, 0.39, 0.74, 1.31, 1.71, 2.1, 2.24, 2.07, 2.41

Produzione

10.86

Modifica: Grazie a DenDenDo per aver suggerito di non usare math.floor per arrotondare e usare int invece di bool per tagliare i caratteri. Lo ricorderò per i puzzle futuri!


Ehi, grazie per i suggerimenti. Ho aggiornato come suggerito.
Darren Breen,

Sembra che tu stia arrotondando a due cifre con le Math.Floor(...)quali non è richiesto. Inoltre, non so se sia possibile in C #, ma di solito puoi usare 1 e 0 per truee false.
DenDenDo

Spiacenti, ho pensato che fosse necessario arrotondare a 2 perché tutti stavano stampando 10.86 e stavo ottenendo 10.866 e arrotondando per eccesso. È possibile per altri linguaggi c ma non per C #. Anche se questo mi ha dato un'idea, ora sto usando 1 e 0 per i miei controlli booleani. Ridotto un po 'di più. Grazie!
Darren Breen,
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.