Handlowiec czasowy w czasie podróży


21

Historia
Dawno temu Bobby stworzył portfel Bitcoin z 1 Satoshi (1e-8 BTC, najmniejsza jednostka walutowa) i zapomniał o tym. Jak wielu innych później pomyślał: „Cholera, gdybym wtedy więcej zainwestował…”.
Nie zatrzymując się na jawie, poświęca cały swój czas i pieniądze na budowę wehikułu czasu. Większość czasu spędza w garażu, nieświadomy światowych spraw i krążących wokół niego plotek. Wykonuje prototyp na dzień przed wyłączeniem prądu z powodu brakujących płatności. Podnosząc wzrok ze swojego stołu roboczego, widzi policyjną furgonetkę, która podjeżdża do jego domu, wygląda tak, jakby wścibscy sąsiedzi myśleli, że prowadzi w swoim garażu laboratorium meta i wezwał gliniarzy.
Nie mając czasu na przeprowadzanie testów, chwyta pamięć USB z danymi dotyczącymi kursów walut z ostatnich lat, łączy kondensator Flux z Quantum Discombobulator i wraca do dnia, w którym stworzył swój portfel

Zadanie
Biorąc pod uwagę dane o kursie wymiany, dowiedz się, ile pieniędzy może zarobić Bobby. Kieruje się bardzo prostą zasadą: „Kupuj taniej - sprzedawaj wysoko”, a ponieważ zaczyna od nieskończenie małego kapitału, zakładamy, że jego działania nie będą miały wpływu na kursy walut z przyszłości.

Wejście
Lista liczb zmiennoprzecinkowych> 0, albo jako ciąg oddzielony pojedynczym znakiem (nowa linia, tabulator, spacja, średnik, cokolwiek wolisz) przekazany do programu jako argument wiersza poleceń, odczytany z pliku tekstowego lub STDIN lub przekazany jako parametr do funkcji. Zamiast ciągów możesz używać numerycznych typów danych lub tablic, ponieważ jest to po prostu ciąg z nawiasami.

Wyjście
Czynnik, przez który kapitał Bobbysa został pomnożony przez koniec handlu.

Przykład

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

Kurs wymiany: 0,48 $ / BTC, ponieważ wkrótce ma spaść, sprzedajemy wszystkie Bitcoiny za 4,8 nanodolara. Współczynnik = 1 Kurs wymiany: 0,4, nic nie rób
Kurs wymiany: 0,24 $ / BTC i rośnie: przelicz wszystkie $ na 2 Satoshis. Współczynnik = 1 (wartość dolara pozostaje niezmieniona)
Kurs wymiany: 0,39 - 2,1 $ / BTC: nic nie rób
Kurs wymiany: 2,24 $ / BTC: sprzedaj wszystko przed spadkiem. 44,8 nanodolara, współczynnik = 9,33
Kurs wymiany: 2,07 $ / BTC: kup 2.164 Satoshis, współczynnik = 9,33
Kurs wymiany: 2,41 $ / BTC: kup 52,15 nanodolara, współczynnik = 10,86

Output: 10.86

Dodatkowe szczegóły
Możesz zignorować dziwne przypadki brzegowe, takie jak stałe dane wejściowe, wartości zerowe lub ujemne, tylko jedna liczba wejściowa itp.
Możesz generować własne liczby losowe do testowania lub korzystania z rzeczywistych wykresów giełdowych. Oto dłuższe dane wejściowe do testowania (Oczekiwany wynik to około 321903884.638)
Krótko wyjaśnij, co robi Twój kod
Grafy są mile widziane, ale nie są konieczne


Jeśli weźmiemy liczby za pomocą argumentu funkcji, czy nadal musi to być ciąg znaków, czy też możemy bezpośrednio wziąć tablicę?
Martin Ender

@ MartinBüttner Zastanawiałem się przez chwilę, bez względu na to, czy dane wejściowe to ciąg znaków, tablica numeryczna czy dowolny wybór, zawsze są pewne języki, które mają przewagę. Wydaje się, że nie ma ogólnego porozumienia w tej sprawie, a pisanie dwóch programów, jednego do wprowadzania liczb i jednego do wprowadzania ciągu znaków i uśredniania obu wyników wydaje się przesadą.
DenDenDo

Co z napędem Infinite Improbability? :)
Klamka

2
Wracając do problemu, czy musimy zaokrąglać wartości BTC i / lub $ z określoną dokładnością, przy każdej iteracji? Na przykład w prawdziwym świecie portfel BTC musi być zaokrąglony do Satoshi. To robi różnicę, ponieważ w twoim przykładzie w 2.07 możesz kupić tylko 2s (nie 2.164); następnie przy 2,41 twoje 2s kupują ci 48,2 n $ (nie 52,15), więc współczynnik wynosi 10,04 (nie 10,86). Chyba że trzymasz osobny portfel $ ze zmianą i musisz za każdym razem go dodawać. Co z dolarami? Czy ktoś może dziś twierdzić, że ma nanodolar? Uważam, że najmniejszą kwotą, jaką można pomieścić, jest 1 cent.
Tobia,

1
@CortAmmon: mówisz, że handel BTC nie jest chaotyczny? ;-)
Steve Jessop

Odpowiedzi:


10

APL, 16 znaków

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

Ta wersja wykorzystuje @Frxstrem „s prostsze algorytm i @xnor ” s max(r,1)pomysł.

Zakłada również, że seria ogólnie rośnie, to znaczy, że pierwsza wartość bitcoin jest mniejsza niż poprzednia. Jest to zgodne z opisem problemu. Aby uzyskać bardziej ogólną formułę, należy upuścić pierwszą parę stawek, dodając 2 znaki:{×/1⌈÷/⊃1↓⍵,¨¯1⌽⍵}

Przykład:

    {×/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

Wyjaśnienie:

Zacznij od danych o kursie wymiany:

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

Sparuj każdy numer z poprzednim (pierwszy zostanie sparowany z ostatnim) i umieść je w macierzy:

    ⎕←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

Zmniejsz każdy rząd przez podział, zachowaj te o stosunku> 1 i połącz współczynniki przez pomnożenie. Wyeliminuje to powtarzające się czynniki w szeregu kolejnych rosnących kursów, a także fałszywy stosunek między pierwszym a ostatnim kursem wymiany:

    ×/1⌈÷/M
10.86634461

Twoje założenie, że zawsze powinieneś sprzedawać na pierwszej pozycji, powoduje, że dłuższy sygnał wejściowy kończy się niepowodzeniem i zwraca liczbę mniejszą niż 1 (co jest oczywiście niemożliwe).
Frxstrem

@ Frrstst dzięki, naprawiono. Teraz daje taki sam wynik jak skrypt. Byłoby bardziej pomocne, gdyby PO dał nam kilka przypadków testowych z wynikami!
Tobia,

1
Uwielbiam dobre rozwiązania APL, ponieważ za każdym razem, gdy na nie patrzę, uruchamiają mój filtr „to bełkot plików binarnych” i zaczynam szukać rozszerzenia pliku, aby dowiedzieć się, jak go otworzyć.
Cort Ammon - Przywróć Monikę

@CortAmmon, co wcale nie jest bezpodstawne: APL zatrudnia kilkudziesięciu operatorów graficznych; na powierzchni mogą przypominać ci symbole z 8-bitowych zestawów znaków DOS. Jest to również bardzo zwięzły język, co oznacza, że ​​linia APL ma bardzo wysoką entropię informacji. Te dwie funkcje łączą się, aby wywołać wrażenie pliku binarnego zrzuconego do okna DOS. Ale trwa to tylko, dopóki nie nauczysz się doceniać piękna symboli i składni APL.
Tobia,

6

Python, 47

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

Przykład uruchom na przypadku testowym .

Zrób listę pływaków. Rekurencyjnie mnoży współczynnik zysku z pierwszych dwóch elementów, aż pozostanie mniej niż dwa elementy. W przypadku podstawowym daje to, Trueco równa się 1.

Użycie popdaje taką samą liczbę znaków.

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

Podobnie dzieje się na końcu listy.

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

Dla porównania, mój iteracyjny kod w Pythonie 2 ma 49 znaków, 2 znaki dłużej

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

Na początek c=-1jest hack, aby wymyślony pierwszy „ruch” nigdy nie przynosił zysków. Uruchomienie produktu -1zamiast 1pozwala nam przypisać oba elementy razem, a my odrzucamy go za darmo przed drukowaniem.


Dłuższa walizka testowa przekracza domyślny limit rekurencji o 1. f (x [: 999]) nadal daje jednak poprawny wynik. Aby uzyskać dłuższy wkład, można go podzielić na części ([n:(n+1)*500 + 1] for n in range(N_elem/500) )i pomnożyć współczynniki cząstkowe
DenDenDo

Limit rekurencji zależy od implementacji; możesz użyć Stackless Python, aby tego uniknąć.
xnor

Lub po prostu użyj sys.setrecursionlimit(w CPython)
user253751

3

Python, 79 81 76 77 bajtów

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

xjest wejściem zakodowanym jako lista. Funkcja zwraca współczynnik.


Może to tylko moja wersja w języku Python, ale musiałem użyć 1.zamiast 1na końcu funkcji, w przeciwnym razie otrzymam TypeError: deskryptor „ mul ” wymaga obiektu „float”, ale otrzymał „int”
Tobia

BTW, inteligentny algorytm!
Tobia,

Nie potrzebujesz tej f=części.
wizzwizz4

2

CJam, 33 bajty

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

Można to dodatkowo pograć w golfa.

Pobiera dane wejściowe ze STDIN, takie jak

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

i przekazuje współczynnik do STDOUT, jak

10.866344605475046

Wypróbuj online tutaj


1

Pyth , 18 lat

u*GeS,1ceHhHC,QtQ1

Wyjaśnienie:

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) pomysł dzięki @xnor


1

C #, 333 , 313

Moja pierwsza próba. Prawdopodobnie mógłbym to bardziej zoptymalizować, ale tak jak powiedziałem pierwszą próbę, więc zrozumiem!

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

Wkład

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

Wydajność

10.86

Edycja: Podziękowania dla DenDenDo za sugestię, aby nie używać math.floor do zaokrąglania i używania int zamiast bool do wycinania znaków. Zapamięta to dla przyszłych łamigłówek!


Hej, dzięki za wskazówki. Zaktualizowałem zgodnie z sugestią.
Darren Breen

Wygląda na to, że zaokrąglasz do dwóch cyfr, Math.Floor(...)które nie są wymagane. Ponadto nie wiem, czy jest to możliwe w języku C #, ale zwykle można użyć 1 i 0 dla truei false.
DenDenDo

Przepraszam, pomyślałem, że zaokrąglenie do 2 było wymagane, ponieważ wszyscy drukowali 10.86, a ja dostawałem 10.866 i zaokrąglałem w górę. Możesz dla innych języków C, ale nie dla C #. Chociaż dało mi to pewien pomysł, teraz używam 1 i 0 do moich czeków logicznych. Trochę go zmniejszyłem. Dzięki!
Darren Breen
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.