Comerciante de ações no tempo

21

História
Há muito tempo, Bobby criou uma carteira de Bitcoin com 1 Satoshi (1e-8 BTC, a menor unidade monetária) e a esqueceu. Como muitos outros, mais tarde ele pensou: "Droga, se eu investisse mais naquela época ...".
Sem parar de sonhar acordado, ele dedica todo seu tempo e dinheiro à construção de uma máquina do tempo. Ele passa a maior parte do tempo em sua garagem, sem saber dos assuntos mundanos e dos rumores que circulam sobre ele. Ele conclui o protótipo um dia antes de sua eletricidade estar prestes a ser desligada devido a pagamentos perdidos. Erguendo os olhos da bancada, vê uma van da polícia estacionando em sua casa, parece que os vizinhos intrometidos pensavam que ele estava dirigindo um laboratório de metanfetamina em sua garagem e chamou a polícia.
Sem tempo para executar testes, ele pega um pendrive com os dados de taxa de câmbio dos últimos anos, conecta o capacitor de fluxo ao discombobulador quântico e se vê transportado de volta ao dia em que criou sua carteira

Tarefa
Dados os dados da taxa de câmbio, descubra quanto dinheiro Bobby pode ganhar. Ele segue uma regra muito simples: "Compre na baixa - venda na alta" e, como ele começa com um capital infinitesimalmente pequeno, assumimos que suas ações não terão impacto nas taxas de câmbio no futuro.

Entrada
Uma lista de valores flutuantes> 0, como uma sequência separada por um único caractere (nova linha, guia, espaço, ponto e vírgula, o que você preferir) transmitida como argumento de linha de comando para o programa, lida de um arquivo de texto ou STDIN ou passada como parâmetro para uma função. Você pode usar tipos de dados numéricos ou matrizes em vez de uma sequência, porque é basicamente apenas uma sequência com colchetes.

Saída
O fator pelo qual o capital da Bobbys se multiplicou até o final da negociação.

Exemplo

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

Taxa de câmbio: 0,48 $ / BTC, já que está prestes a cair, vendemos todos os Bitcoins por 4,8 nanodólares. Fator = 1 Taxa de câmbio: 0,4, não faça nada
Taxa de câmbio: 0,24 $ / BTC e subida: converta todos os $ em 2 Satoshis. Fator = 1 (o valor do dólar ainda permanece inalterado)
Taxa de câmbio: 0,39 - 2,1 $ / BTC: não faça nada
Taxa de câmbio: 2,24 $ / BTC: venda tudo antes da queda. 44,8 nanodólares, fator = 9,33
Taxa de câmbio: 2,07 $ / BTC: compra 2,164 Satoshis, fator = 9,33
Taxa de câmbio: 2,41 $ / BTC: compra 52,15 nanodólares, fator = 10,86

Output: 10.86

Detalhes adicionais
Você pode ignorar casos extremos estranhos, como entrada constante, valores zero ou negativos, apenas um número de entrada, etc.
Fique à vontade para gerar seus próprios números aleatórios para testar ou usar gráficos de ações reais. Aqui está uma entrada mais longa para teste (saída esperada aprox. 321903884.638)
Explique brevemente o que seu código faz
Gráficos são apreciados, mas não são necessários

DenDenDo
fonte
Se pegarmos os números por meio do argumento de função, ele ainda precisa ser uma string ou poderíamos pegar uma matriz diretamente?
Martin Ender
@ MartinBüttner Pensei nisso por um tempo, se a entrada é uma string, uma matriz numérica ou uma escolha livre, sempre há alguns idiomas que obtêm uma vantagem. Parece não haver um consenso geral sobre isso, e escrever dois programas, um para entrada numérica e outro para entrada de string, e calcular a média de ambas as pontuações parece um exagero.
DenDenDo
E a Unidade de Improbabilidade Infinita? :)
Maçaneta da porta
2
Voltando ao problema, precisamos arredondar os valores BTC e / ou $ com uma precisão específica, a cada iteração? Por exemplo, no mundo real, a carteira BTC de uma pessoa deve ser arredondada para o Satoshi. Isso faz a diferença, porque no seu exemplo, em 2.07, você pode comprar apenas 2s (não 2.164); então, em 2,41, seus 2s compram 48,2 n $ (não 52,15), então o fator é 10,04 (não 10,86). A menos que você mantenha uma carteira $ separada com a alteração e precise adicioná-la novamente a cada vez. E quanto a dólares? Hoje alguém pode afirmar ter um nanodólar? Eu acredito que a menor quantidade que se pode guardar é 1 ¢.
Tobia
11
@CortAmmon: você está dizendo que a negociação BTC não é caótica? ;-)
Steve Jessop

Respostas:

10

APL, 16 caracteres

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

Esta versão utiliza @Frxstrem 's mais simples algoritmo e @xnor ' s max(r,1)idéia.

Ele também assume que a série está aumentando globalmente, ou seja, o primeiro valor do bitcoin é menor que o último. Isso é consistente com a descrição do problema. Para obter uma fórmula mais geral, as primeiras taxas devem ser descartadas, adicionando 2 caracteres:{×/1⌈÷/⊃1↓⍵,¨¯1⌽⍵}

Exemplo:

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

Explicação:

Comece com os dados da taxa de câmbio:

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

Emparelhe cada número com o anterior (o primeiro será emparelhado com o último) e coloque-os em uma matriz:

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

Reduza cada linha por divisão, mantenha aquelas com razão> 1 e combine as proporções por multiplicação. Isso eliminará todos os fatores repetidos consecutivos de taxas crescentes sucessivas, bem como a proporção espúria entre a primeira e a última taxa de câmbio:

    ×/1⌈÷/M
10.86634461
Tobia
fonte
Sua suposição de que você sempre deve vender na primeira posição faz com que a entrada mais longa falhe e retorne um número menor que 1 (o que é obviamente impossível).
Frxstrem
@Frxstrem obrigado, corrigido. Agora, ele fornece o mesmo resultado que o seu script. Teria sido mais útil se o OP tivesse nos dado alguns casos de teste com resultados!
Tobia
11
Adoro boas soluções de APL porque, sempre que olho para elas, elas acionam o filtro "este é um conjunto de arquivos binários" e começo a procurar uma extensão de arquivo para descobrir como abri-la.
Cort Ammon - Restabelece Monica
@CortAmmon que não é de todo infundado: a APL emprega muitas dezenas de operadores gráficos; na superfície, eles podem lembrá-lo dos símbolos dos conjuntos de caracteres do DOS de 8 bits. É também uma linguagem muito concisa, o que significa que uma linha de APL possui entropia de informações muito alta. Esses dois recursos se combinam para acionar a sensação de um arquivo binário despejado em uma janela do DOS. Mas dura apenas até você aprender a apreciar a beleza dos símbolos e sintaxe da APL.
Tobia
6

Python, 47

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

Exemplo executado no caso de teste .

Faça uma lista de carros alegóricos. Multiplica-se recursivamente no fator de lucro dos dois primeiros elementos até restarem menos de dois elementos. Para o caso base, dá Truequal é igual 1.

Usar popfornece o mesmo número de caracteres.

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

O mesmo acontece no final da lista.

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

Para comparação, meu código iterativo no Python 2 tem 49 caracteres, 2 caracteres a mais

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

Começando com c=-1é um truque para fazer o primeiro "movimento" imaginário nunca mostrar lucro. Iniciar o produto em -1vez de 1nos permitir atribuir os dois elementos juntos, e nós o devolvemos gratuitamente antes de imprimir.

xnor
fonte
A caixa de teste mais longa excede o limite de recursão padrão em 1. f (x [: 999]) ainda fornece o resultado correto. Para entrada mais longa, você pode dividi-la em partes ([n:(n+1)*500 + 1] for n in range(N_elem/500) )e multiplicar os fatores parciais
DenDenDo
O limite de recursão depende da implementação; você pode usar o Stackless Python para evitá-lo.
Xnor
Ou apenas use sys.setrecursionlimit(no CPython)
user253751
3

Python, 79 81 76 77 bytes

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

xé a entrada codificada como uma lista. A função retorna o fator.

Frxstrem
fonte
Talvez seja apenas a minha versão do Python, mas eu tive que usar em 1.vez de 1no final da função, caso contrário, recebo TypeError: o descritor ' mul ' requer um objeto 'float' mas recebeu um 'int'
Tobia
BTW, algoritmo inteligente!
Tobia
Você não precisa dessa f=parte.
Wizzwizz4
2

CJam, 33 bytes

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

Isso pode ser jogado ainda mais.

Recebe entrada de STDIN, como

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

e gera o fator para STDOUT, como

10.866344605475046

Experimente online aqui

Optimizer
fonte
1

Pyth , 18

u*GeS,1ceHhHC,QtQ1

Explicação:

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) ideia graças a @xnor

isaacg
fonte
1

C #, 333 , 313

Minha primeira tentativa. Provavelmente poderia otimizá-lo mais, mas como eu disse na primeira tentativa, o problema será resolvido !.

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

Entrada

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

Saída

10.86

Edit: Obrigado DenDenDo por sugerir não usar math.floor para arredondar e usar int em vez de bool para cortar caracteres. Lembre-se disso para futuros quebra-cabeças!

Darren Breen
fonte
Ei, obrigado pelas dicas. Eu atualizei como sugerido.
precisa saber é o seguinte
Parece que você está arredondando para dois dígitos com os Math.Floor(...)quais não é necessário. Além disso, eu não sei se é possível em c #, mas geralmente você pode usar 1 e 0 para truee false.
DenDenDo
Desculpe, pensei que o arredondamento para 2 era necessário, porque todo mundo estava imprimindo 10,86 e eu estava recebendo 10,866 e arredondando. Você pode para outros idiomas c, mas não para c #. Embora isso tenha me dado uma idéia, agora estou usando 1 e 0 para minhas verificações booleanas. Reduzi um pouco mais. Obrigado!
precisa saber é o seguinte