Торговец акциями во времени


21

История
Давным-давно Бобби создал биткойн-кошелек с 1 сатоши (1e-8 BTC, самая маленькая единица валюты) и забыл об этом. Как и многие другие, он позже, хотя: «Черт, если бы я вложил больше тогда ...».
Не останавливаясь на мечтах, он посвящает все свое время и деньги на создание машины времени. Он проводит большую часть своего времени в своем гараже, не подозревая о мирских делах и слухах, циркулирующих вокруг него. Он завершает создание прототипа за день до того, как его электричество вот-вот отключится из-за пропущенных платежей. Поднявшись со своего рабочего места, он видит полицейский фургон, подъезжающий к его дому, похоже, что любопытные соседи подумали, что он работает в своей лаборатории, и вызвали полицию.
Не имея времени для проведения тестов, он берет USB-флешку с данными обменного курса за последние годы, подключает конденсатор Flux к квантовому дискомбобулятору и обнаруживает, что его транспортируют обратно в тот день, когда он создал свой кошелек.

Задача
С учетом данных о валютном курсе выяснить, сколько денег может заработать Бобби. Он следует очень простому правилу: «покупай дешево - продавай дорого», и, поскольку он начинает с бесконечно малого капитала, мы предполагаем, что его действия не окажут влияния на обменные курсы в будущем.

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

Выходные данные
Коэффициент, на который капитал Bobbys умножается на конец торгов.

пример

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 вы можете купить только 2s (не 2.164); затем в 2,41 ваши двойки покупают вам 48,2 н.д. (не 52,15), поэтому коэффициент равен 10,04 (не 10,86). Если у вас нет отдельного кошелька $ с изменением и вам нужно каждый раз добавлять его обратно. А как насчет долларов? Может ли кто-нибудь сегодня претендовать на нанодоллар? Я считаю, что наименьшая сумма, которую можно держать, составляет 1 ¢.
Tobia

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 спасибо, исправлено. Теперь он дает тот же результат, что и ваш скрипт. Было бы более полезно, если бы ОП дал нам несколько тестовых случаев с результатами!
Tobia

1
Мне нравятся хорошие APL-решения, потому что, когда я на них смотрю, они запускают мой фильтр «это бинарный файл», и я начинаю искать расширение файла, чтобы выяснить, как его открыть.
Cort Ammon - Восстановить Монику

@CortAmmon, что вовсе не беспочвенно: в APL работают десятки графических операторов; на поверхности они могут напоминать вам символы из 8-битных наборов символов DOS. Это также очень краткий язык, означающий, что линия APL обладает очень высокой информационной энтропией. Эти две функции объединяются, чтобы вызвать ощущение двоичного файла, сброшенного в окно DOS. Но это длится только до тех пор, пока вы не научитесь ценить красоту символов и синтаксиса APL.
Tobia

6

Python, 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)
user253751

3

Python, 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

Кстати, умный алгоритм!
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.