fundo
Em alguns futuros possíveis, o mundo converterá seus sistemas numéricos de decimal (base 10 ou b10
) para outra base (binária b2
, octal b8
, hexadecimal b16
ou até unária b1
, caso em que estamos ferrados!). Assim, em preparação para esse possível evento de mudança mundial, você decide fazer a prova de base de todos os seus programas. Isto pode ser feito usando apenas singulares 0
s e 1
s em conjunto com os operadores para substituir as constantes numéricas existentes.
No entanto, há apenas um problema: você tem uma tonelada de programas para alterar e a conversão manual de cada número em uma expressão levaria semanas! Assim, você decide escrever um programa (ou função) para decidir qual expressão deve substituir cada número.
Entrada
A entrada será um número inteiro positivo. Seu código deve ser capaz de lidar com qualquer número inteiro de até 1000.
(Se o seu código suportar entradas decimais e / ou negativas, consulte Pontuação abaixo.)
Saída
Seu código deve gerar uma expressão que seja avaliada para a entrada em pelo menos um idioma. Este pode ser qualquer idioma; não precisa ser o mesmo em que seu programa ou função está escrito. Além disso, essa expressão não precisa ser um programa ou função completo.
Para maior clareza, a saída pode conter qualquer uma destas operações:
- incremento / decremento
- adicionar / somar
- subtrair / negar
- multiplicar / dobrar (apenas se não envolver diretamente o número
2
!) - dividir / módulo
- expoentes / logaritmos
- square / sqrt (novamente, apenas se estes não envolverem diretamente o número
2
!) - operações bit a bit (bOR, BAND, bNOT, bXOR, troca de bits)
- configurando / obtendo variáveis
- manipulação de pilha
Você não pode usar eval()
ou quaisquer funções semelhantes na saída. Você também não pode usar na saída quaisquer funções que executem uma (s) ação (ões) além das mencionadas acima.
Ah, e mais uma coisa: como queremos que a saída seja válida no maior número de bases possível, as únicas constantes de número que ela pode conter são 0
e 1
. Números como 10
(dez) não são permitidos, a menos que o idioma o interprete como a 1
e a 0
. O uso de strings para conter números também não é permitido, assim como o uso de caracteres como CJam's A
- K
(que representam 10
- 20
).
Casos de teste
(Todas as saídas estão em JavaScript, mas podem funcionar em outros idiomas.)
Entrada 1:
2
Possível saída 1:
1+1
Entrada 2:
13
Saída possível 2:
(a=1+1+1)*a+a+1
Entrada 3:
60
Possível saída 3:
(b=(a=1+1+1+1)*a)*a-a
Entrada 4:
777
Saída possível 4:
(c=(b=((a=1+1+1+1)*a-a+1)*a)*a+b)+c+c-a+1
Entrada 5:
1000
Saída possível 5:
Math.pow((a=1+1+1)*a+1,a)
Pontuação
O objetivo desse desafio é reduzir o máximo possível a saída do seu código. Sua pontuação será calculada desta maneira:
Pontuação básica: a contagem média de bytes de todas as saídas para números inteiros de 1 a 1000.
Pontuação decimal: se o seu código suportar pelo menos três casas decimais, essa é a contagem média de bytes de todas as saídas da sequência de números começando
0.001
e terminando em1000
, aumentando a1.001
cada vez.0.001, 1.002, 2.003...998.999, 1000.000
Então tire 50% dessa pontuação.Pontuação negativa: se o seu código suportar números negativos e zero, esta é a contagem média de bytes das saídas de todos os números inteiros de
-1000
até0
. Em seguida, tire 10% dessa pontuação.
(A maneira mais fácil de calcular isso provavelmente seria um loop com seu programa / função dentro.)
Sua pontuação final é a média de qualquer uma das fórmulas acima.
Se a saída for não determinística (ou seja, um pouco aleatória; várias execuções com a mesma entrada produzem várias saídas exclusivas), a pontuação de cada entrada é determinada pela maior saída em dez execuções na minha CPU.
Além disso, como você não sabe como serão preciosos os dados do computador no futuro, a contagem de bytes do código do gerador deve ser menor que 512 bytes.
A pontuação mais baixa em duas semanas (em 30 de setembro) será declarada vencedora. Parabéns ao seu vencedor, @ThomasKwa !
Entre os melhores
Para garantir que sua resposta seja exibida corretamente, inicie-a com este cabeçalho:
# Language name/Other language name, X points
Onde X
está a pontuação da sua resposta. Exemplo:
# CJam/Pyth, 25.38 points
Se você tiver alguma dúvida ou sugestão, entre em contato. Boa sorte!
fonte
0
ou1
por padrão?Integer.parseInt("1000", 1+1+1+1+1+1+1+1+1+1)
? Tenho certeza de queparseInt
usa apenas a operações permitidas ;-)Respostas:
Código da máquina Python / Zilog Z80,
11.65311.488Bônus: números negativos.
Supõe que o
hl
par de registradores inicialmente contenha 0 e retorne o resultado emhl
.Somente estas três instruções são usadas:
Utilizamos uma pequena modificação da representação binária equilibrada de peso mínimo BBR2 . Como o BBR2 minimiza o peso (número de dígitos diferentes de zero), mas queremos minimizar o peso mais o número de trocas de bits, alteramos uma constante no algoritmo de
3/2
para5/3
.Para calcular a pontuação e verificar, use este código:
Exemplo de saída:
Ou na montagem:
Mais exemplos de programas:
Otimizações possíveis: regras OP que os
inc h
edec h
instruções, que mudam diretamente o byte superiorhl
, são ilegais, massla h
e os indocumentadossl1 h
(turnos esquerda pouco a 1 sobreh
essa mudança em um0
e1
são permitidas, respectivamente).sla h
esl1 h
têm dois bytes cada, mas às vezes podem reduzir a saída.fonte
+
traduzdec
. Eu continuo lendo os exemplos negativos erradamente.CJam / CJam,
143.26342.71328.89923.90121.90320.468Nenhum bônus se aplica.
Experimente online: exemplo de execução | calculadora de pontuação | verificação
Execuções de exemplo
fonte
%
um por uma expressão mais longa. Os links devem funcionar agora.ß / BrainFuck, 34.201 pontos
fonte ß (194B):
Se alguém estiver interessado, adicionarei uma explicação. A saída BF já está bastante otimizada, mas acho que eu poderia usar o restante 318B de código ß para implementar
remoção de colisão do operador.Amostras:
Correndo no Windows:
Rodando em Linux:
Valide no intérprete online de BF .
Pontuações:
= 37.495
.= 60.959 * 0.5 = ~30.48
.= 38.4765234765235 * 0.9 = ~34.629
= (37.495 + 30.48 + 34.629)/3 = 34.201
.fonte
Ruby / Ruby, 29.77885
31,873 * 0,9 (negativo) 30,872 (positivo).
A estratégia básica é a representação simétrica da base 3 ("ternário balanceado"), ou seja, quando os dígitos estão em
-1,0,1
vez de0,1,2
Aqui está a saída de 0 a 40 antes da limpeza
E após a limpeza
fonte
Ceilão / Ceilão,
49,8640,95 pontosA terceira versão usa o Ceilão 1.2 para o gerador e 509 bytes de código:
import ceylon.language{S=String,I=Integer,e=expand}S q(I n)=>n==0then"0"else(n<0then"-"+p(-n,"-")else p(n,"+"));variable Map<[I,S],S>c=map{};S p(I n,S s){S v=c[[n,s]]else(n<8then s.join([1].repeat(n)))else(let(a="+-".replace(s,""))e(e{for(x in 2..8)let(l=(n^(1.0/x)).integer){for(r in l:2)if(r>1)let(w=r^x){if(w-n<n)"("+p(r,"+")+")^("+p(x,"+")+")"+(w<n then s+p(n-w,s)else(n<w then a+p(w-n,a)else""))}}}).reduce<S>((x,y)=>x.size<y.size then x else y))else"";c=[n,s]in c then c else map{[n,s]->v,*c};return v;}
Ele chega a 35,22 pontos, mas não vou colocar isso na linha de título porque o Celyon 1.2 foi publicado apenas em 29 de outubro. Acho que não seria capaz de implementar esse algoritmo no Ceilão 1.1 nesse tamanho.). Mais detalhes lá embaixo, aqui vou descrever a segunda versão. (A primeira versão pode ser vista na história - suportava apenas números positivos, mas cabia em 256 bytes.)
Segunda versão
Agora, a segunda versão, que suporta números inteiros negativos (e 0), e geralmente cria uma saída um pouco mais curta usando além disso
-
. (Esta versão realmente usa o comprimento permitido, o primeiro tentou permanecer com menos de 256 bytes em vez de 512.)O código tem comprimento 487, então ainda há espaço para mais otimizações posteriormente. (Também existem muitas reservas em forma de espaço em branco e nomes longos de variáveis.)
A pontuação:
Algumas saídas de amostra:
Como você pode ver, os negativos são sempre um byte (o principal
-
) mais longo que os positivos correspondentes.A idéia base é a mesma do programa anterior: encontre um quadrado próximo ao número de destino e represente sua raiz e o restante recursivamente. Mas agora permitimos que nosso quadrado também seja um pouco maior que o número alvo, o que torna o restante negativo. (O valor
+0.5
pode ser alterado para uma constante diferente para ajustar o algoritmo, mas parece que eu já atingi o ideal aqui - 0,4 e 0,6 dão resultados piores.)Para tornar negativos os valores negativos (e, de outra forma, ter a mesma estrutura que os positivos, passamos o operador
sign
para nossa função recursivap
-"+"
ou seja, ou é)"-"
. Podemos usar isso para o marceneiro nos casos triviais (ou seja, n <9) também quanto ao restante, se for positivo, e use o sinal oposto para o restante, se for negativo.A
proof
função lida com o sinal inicial (com um caso especial para 0), ap
função faz o trabalho real, com recursão.Terceira versão, para o Ceilão 1.2
A versão em golf (por exemplo, comentários e espaços em branco removidos) é postada na parte superior, com exatamente 509 bytes de código.
Isso usa o mesmo princípio básico da segunda versão, mas, em vez de apenas quadrados, também tenta usar potências de números mais altas (tentando expoentes de 2 a 8) e usa o resultado mais curto. Ele também armazena em cache os resultados, caso contrário isso seria inaceitavelmente lento para números maiores com muitas chamadas recursivas.
Pontuação:
A grande construção recuada no meio são três compreensões iteráveis aninhadas, as duas internas dentro de uma expressão let. Eles são aninhados usando a função de expansão duas vezes e a
reduce
função encontra o menor desses caracteres.Arquivei uma solicitação de recurso para poder fazer isso em uma única compreensão.
Dentro da compreensão, estamos construindo uma cadeia a partir da raiz
r
, do expoentex
e do restante (n-w
ouw-n
).A
let
expressão e amap
função são novas no Ceilão 1.2.map
poderia ter sido substituído porHashMap
(que precisaria de mais caracteres para a importação, embora provavelmente fosse ainda mais rápido, pois eu não criaria o mapa novo para cada nova entrada). Aslet
expressões likelet (w = r ^ x)
poderiam ter sido substituídas usando umaif
cláusula likeif(exists w = true then r ^ x)
(e então eu também não precisaria das duasexpand
chamadas), mas isso ainda seria um pouco mais longo, não cabendo nos 511 bytes permitidos.Aqui, as saídas de amostra correspondentes às selecionadas acima, todas elas, exceto os números realmente pequenos, são mais curtas:
Por exemplo, agora temos 1000 = (3 ^ 2 + 1) ^ 3, em vez de 1000 = (6 ^ 2-4) ^ 2-5 ^ 2 + 1.
fonte
less than 512
. Sou você pode usar um max. de 511 bytes;)Ruby / dc,
20.29618,41416,968Programaçao dinamica! Define uma lista de funções que, dadas uma instrução dc, retornam uma nova expressão e o valor numérico dessa expressão. Em seguida, começando com
1
prefinado, ele cria uma lista de todos os valores alcançáveis, incluindo o valor desejado.editar:
Adicionou uma função para n-1 e fez executar o algoritmo através de várias passagens. Parece precisar de 7 passes para estabilizar. Teve que diminuir alguns nomes de variáveis para permanecer dentro de 512 bytes.
editar 2:
Adicionadas funções para n (n-1) , n (n + 1) e n ^ 3 enquanto eu estava nisso. Encurtou o código um pouco mais, chegando a exatamente 512 bytes.
Números gerados:
A saída consiste inteiramente em cinco caracteres diferentes:
1
empurra o valor 1 na pilha;d
duplica a parte superior da pilha;+
,-
, E*
aparece os dois valores superior e empurra a sua soma, diferença, e do produto, respectivamente. Cada expressão gerada adiciona apenas um valor à pilha após a execução....
fonte
-
operador enquanto permanecer na contagem de bytes?Python 2.6,
78.069- 66.265 pontosEnviando minha resposta para o que vale a pena (não muito nesse caso ... mas demonstrando claramente que, para esse desafio, não basta pensar em compor a saída como uma soma de valores com deslocamento de bit; quando levados em conta que nenhum dígito fora de 0 ou 1 pode aparecer na saída). Posso voltar mais tarde com uma maneira diferente de gerar saída.
O código em si não é muito longo (176 caracteres):
Ele gera uma saída correta, mas detalhada:
Snippet que calcula a pontuação:
fonte