Подорож у бік часу торговець


21

Історія
Давно Боббі створив біткойн-гаманець з 1 сатоші (1e-8 BTC, найменша валютна одиниця) і забув про це. Як і багато інших, він пізніше, хоча "Чорт, якби я тоді більше інвестував ...".
Не зупиняючись на мріянні, він присвячує весь свій час і гроші на побудову машини часу. Він проводить більшу частину часу в своєму гаражі, не знаючи про мирські справи та чутки, що про нього кружляють. Він завершує прототип за день до того, як його електроенергія буде відключена через пропущені платежі. Очікуючись зі свого робочого столу, він бачить, як під'їжджає до його будинку міліцейський фургон, схожий на те, що стомлені сусіди подумали, що він керує мет-лабораторією у своєму гаражі та викликав поліцейських.
Не встигаючи проводити тести, він забирає USB-накопичувач із даними валютних курсів минулих років, підключає конденсатор флюсу до квантового дискомболятора і переносить його назад до дня, коли створив свій гаманець.

Завдання
З огляду на дані валютного курсу, з’ясуйте, скільки грошей може заробити Боббі. Він дотримується дуже простого правила: "Купуйте низький - продайте високий", і оскільки він починається з нескінченно малого капіталу, ми припускаємо, що його дії не матимуть впливу на валютні курси в майбутньому.

Введення
Список поплавків> 0, або як рядок, розділений одним символом (новий рядок, вкладка, пробіл, крапка з комою, що завгодно більше), передається як аргумент командного рядка до програми, зчитується з текстового файлу або STDIN або передається як параметр до функції. Ви можете використовувати числові типи даних або масиви замість рядка, оскільки в основному це лише рядок із дужками.

Вихідний
коефіцієнт, на який капітал Боббіса помножився на кінець торгів.

Приклад

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

Курс валют: 0,48 $ / BTC, оскільки він скоро знизиться, ми продаємо всі біткойни за 4,8 нанодоларів. Коефіцієнт = 1 Курс валют: 0,4, нічого не робити
Курс валют: 0,24 $ / BTC і зростання: конвертувати всі $ у 2 сатоши. Коефіцієнт = 1 (значення долара залишається незмінним)
Курс валют: 0,39 - 2,1 $ / BTC: нічого не робити
Курс валют: 2,24 $ / BTC: продати все до падіння. 44,8 нанодолярних, коефіцієнт = 9,33
Курс валют: 2,07 $ / BTC: купити 2,164 сатоші, коефіцієнт = 9,33
Курс валют: 2,41 $ / BTC: купити 52,15 нанодолярних, коефіцієнт = 10,86

Output: 10.86

Додаткові деталі
Ви можете ігнорувати дивні
випадкові випадки, такі як постійне введення, нульові або негативні значення, лише одне вхідне число тощо. Не соромтеся генерувати власні випадкові числа для тестування або використання фактичних графіків запасів. Ось довший вклад для тестування (очікуваний вихід приблизно 321903884.638)
Коротко поясніть, що робить ваш код.
Графіки оцінюються, але не потрібні


Якщо ми беремо числа за допомогою аргументу функції, чи все-таки це повинен бути рядок, чи ми могли б безпосередньо взяти масив?
Мартін Ендер

@ MartinBüttner Я деякий час обмірковував це, чи є вхідним рядком, числовим масивом чи вільним вибором, завжди є деякі мови, які отримують перевагу. З цього питання, мабуть, немає загальної думки, і написання двох програм, однієї для числового і однієї для введення рядків і усереднення обох балів, здається, перевищенням.
DenDenDo

А як щодо нескінченного приводу неможливості? :)
Дверна ручка

2
Повертаючись до проблеми, чи потрібно нам округлювати значення BTC та / або $ із заданою точністю на кожній ітерації? Наприклад, у реальному світі гаманець BTC повинен бути закруглений до сатоші. Це має значення, оскільки у вашому прикладі за 2,07 можна придбати лише 2 (не 2,164); то за 2,41 ваші 2 покупці купують вам 48,2 n $ (не 52,15), тому коефіцієнт становить 10,04 (не 10,86). Якщо ви не зберігаєте окремий $ гаманець зі зміною та не потребуєте додавання його кожного разу. А що з доларами? Чи може сьогодні хтось претендувати на наявність нанодоллара? Я вважаю, що найменша сума, яку можна взяти, - 1 ¢.
Тобія

1
@CortAmmon: ти кажеш, що торгування BTC не хаотично? ;-)
Стів Джессоп

Відповіді:


10

APL, 16 символів

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

Ця версія використовує @Frxstrem «S простий алгоритм і @xnor » сек max(r,1)ідею.

Також передбачається, що серія в цілому зростає, тобто перше значення біткойна менше, ніж остання. Це відповідає опису проблеми. Щоб отримати більш загальну формулу, першу пару ставок потрібно скинути, додавши 2 знаки:{×/1⌈÷/⊃1↓⍵,¨¯1⌽⍵}

Приклад:

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

Пояснення:

Почніть з даних валютного курсу:

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

З'єднайте кожне число з попереднім (перше буде спарене з останнім) і введіть їх у матрицю:

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

Зменшуйте кожен рядок на ділення, зберігайте співвідношення> 1 і комбінуйте співвідношення множенням. Це усуне будь-які повторювані фактори підряд послідовно зростаючих курсів, а також помилкове співвідношення між першим та останнім курсами валют:

    ×/1⌈÷/M
10.86634461

Ваша припущення, що ви завжди повинні продавати на першій позиції, робить більш тривалий вхід невдалим і повертає число менше 1 (що, очевидно, неможливо).
Frxstrem

@Frxstrem спасибі, виправлено. Тепер це дає такий же результат, як і ваш сценарій. Було б корисніше, якби ОП дало нам кілька тестових випадків з результатами!
Тобія

1
Я люблю хороші рішення APL, тому що, коли я дивлюся на них, вони спрацьовують мій фільтр "це бінарні файли," і я починаю шукати розширення файлу, щоб зрозуміти, як його відкрити.
Корт Аммон - Відновіть Моніку

@CortAmmon це зовсім не безпідставно: APL працює у багатьох десятках графічних операторів; на поверхні вони можуть нагадувати вам символи з 8-бітових наборів символів DOS. Це також дуже лаконічна мова, це означає, що лінія APL має дуже високу інформаційну ентропію. Ці дві функції поєднуються, щоб викликати відчуття бінарного файлу, скинутого у вікно DOS. Але це триває лише до тих пір, поки ви не навчитеся цінувати красу символів та синтаксису APL.
Тобія

6

Пітона, 47

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

Приклад запуску на тестовому випадку .

Візьміть список поплавців. Рекурсивно множиться на коефіцієнт прибутку з перших двох елементів, поки не залишиться менше двох елементів. Для базового випадку дає, Trueякий дорівнює 1.

Використання popдає однакову кількість символів.

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

Так і відбувається з кінця списку.

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

Для порівняння, мій ітеративний код у Python 2 становить 49 знаків, на 2 символи довше

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

Почати з c=-1хакету, щоб уявний перший «крок» ніколи не показував прибуток. Якщо продукт запускається, -1а не 1дозволяє нам разом привласнювати обидва елементи, і ми негативно відкидаємо його перед друком.


Більш довгий тест перевищує встановлену за замовчуванням ліміт рекурсії на 1. f (x [: 999]) все ж дає правильний результат. Для більш тривалого введення ви можете розділити його на шматки ([n:(n+1)*500 + 1] for n in range(N_elem/500) )та помножити часткові коефіцієнти
DenDenDo

Ліміт рекурсії залежить від реалізації; ви можете використовувати Stackless Python, щоб уникнути цього.
xnor

Або просто скористайтеся sys.setrecursionlimit(у CPython)
користувач253751

3

Пітон, 79 81 76 77 байт

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

x- це вхід, кодований як список. Функція повертає фактор.


Можливо, це просто моя версія Python, але мені довелося використовувати 1.замість 1кінця функції, інакше я отримую TypeError: дескриптор ' mul ' вимагає об'єкт 'float', але отримав 'int'
Tobia

BTW, розумний алгоритм!
Tobia

Вам не потрібна ця f=частина.
wizzwizz4


1

Піт , 18

u*GeS,1ceHhHC,QtQ1

Пояснення:

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) ідея завдяки @xnor


1

C #, 333 , 313

Моя перша спроба. Можливо, можливо, оптимізуйте це більше, але, як я вже сказав, перша спроба, так і отримаєте висіти!

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

Вхідні дані

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

Вихідні дані

10.86

Редагування: Дякуємо DenDenDo за те, що він запропонував не використовувати math.floor для округлення та використання int замість bool для скорочення символів. Згадаймо це для майбутніх пазлів!


Хея, дякую за поради. Я оновив, як було запропоновано.
Даррен Брін

Схоже, ви округляєте до двох цифр, Math.Floor(...)які не потрібно. Крім того, я не знаю, чи можливо це в C #, але зазвичай ви можете використовувати 1 і 0 для trueі false.
DenDenDo

Вибачте, думка закруглення до 2 потрібна, тому що всі друкували 10,86, а я отримував 10,866 і округлював. Можна для інших мов c, але не для C #. Хоча це і дало мені ідею, тому зараз я використовую 1 і 0 для моїх булевих перевірок. Скоротивши це трохи більше. Спасибі!
Даррен Брін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.