Nenhuma ramificação, por favor

14

Qualquer um que esteja moderadamente otimizado para o código de baixo nível conhece os perigos da ramificação, seja ela implementada como instruções if, loops ou instruções select, a possibilidade de uma previsão incorreta de ramificação é uma terrível perda de tempo.

Problemas simples podem ser resolvidos muito melhor com aritmética simples, então vamos fazer isso.

Para os seguintes problemas, todas as variáveis ​​são números inteiros não assinados de 32 bits e o único código permitido são instruções de conjunto simples que envolvem apenas os seguintes operadores:

+ addition
- subtraction
* multiplication
/ integer division, rounds down, division by 0 not allowed
% modulo
& binary and
| binary or
^ binary exclusive or
>> bitshift right
<< bitshift left

Logic operators, return 1 if the expression is true and 0 if it is false.
== equal
!= not equal
< less than
<= less than or equal
> greater than
>= greater than or equal

Set operator
=

Cada linha deve consistir em um identificador de variável seguido por um operador set, seguido por uma expressão.

Uma expressão pode não conter operadores de conjunto adicionais, mas pode conter identificadores de variáveis, números literais e parênteses.

A pontuação do golfe deve contar apenas o número de operadores.

Exemplo:

myvar = ( ( ( foo + 5 ) * bar ) % 7 ) == 3

Tem uma pontuação de 5 operadores.

Uma solução pode incluir tantas variáveis ​​quanto o autor entender.
Variáveis ​​que não foram definidas têm valor 0.
Estouro positivo e negativo é permitido, todos os números negativos estouro negativo, então 3 - 5é 4294967294, como parte de uma instrução maior.

Tarefa 1: Máx.

Dois valores Ae Bexistem no escopo fazem com que a RESULTvariável contenha o maior desses valores quando o programa termina.

Tarefa 2: mediana

Três valores, A, Be C, existem no escopo, fazer a RESULTvariável conter a mediana desses valores quando o termina do programa.

Tarefa 3: Raiz quadrada

Um valor, Aexiste no escopo, faz com que a RESULTvariável contenha a raiz quadrada de A, arredondada para baixo, quando o programa termina.

Não há problema em postar uma resposta para apenas uma ou duas das perguntas; para alguns de vocês, encontrar soluções válidas será um desafio.

aaaaaaaaaaaa
fonte
Onde estão os operadores unários? Eu não me importo, -mas ~poderia ser legal (mesmo que eu não saiba para quê).
John Dvorak
Claro, 0xFFFF_FFFF_FFFF_FFFF ^ xe 0 - x. Como eu pude esquecer?
John Dvorak
@JanDvorak Fez a descrição mais curto, para a lógica de integridade não !é também bastante trivial: x == 0.
Aaaaaaaaaaaa 11/09
Qual é o comportamento da divisão por zero?
John Dvorak
No Mathematica (a> b) retorna Verdadeiro ou Falso. Boole converte Falso em 0 e Verdadeiro em 1. É legal usar Boole[a-b]?
DavidC

Respostas:

5

Tarefa 3, 23 ops

x = (A >> 16) + A / ((A >> 13) + 511) + 15
x = (x + A/x) >> 1
x = (x + A/x) >> 1
x = (x + A/x) >> 1
RESULT = x - (x > A/x)

Usando o método de Newton, como as outras soluções, com uma semente escolhida com mais tato. O primeiro bit A >> 16mantém o topo da faixa feliz, o segundo bit A / ((A >> 13) + 511)mantém o meio da faixa feliz e o último bit 15o inferior, além de impedir a divisão por erros zero (15 é o maior valor possível que permite 0convergir corretamente - pela metade correção três vezes menos igual a zero). Para os valores de entrada 225, 275625, 82137969, 2908768489(e valores próximos), a semente inicial é exata. Todos os casos de borda (quadrados perfeitos, quadrados perfeitos + 1 e quadrados perfeitos - 1) na faixa 0 .. 2**32-1foram testados e estão corretos.

Alguns comentários sobre as regras: O
estouro e o estouro são permitidos, todos os números negativos estão vazios; portanto, 3 - 5 é 4294967294, mesmo como parte de uma declaração maior .

Essa última parte acaba sendo uma espécie de matadora de inovação. Inicialmente, tentei uma solução usando uma forma generalizada do método de Halley , mas percebi que era inválida, dada a restrição acima. A iteração (aplicada às raízes quadradas) é a seguinte:

x = x * (3*A + x*x) / (A + 3*x*x)

Essa iteração possui boas qualidades que a de Newton não possui. Ele converge cubicamente (em vez de quadraticamente), converge de cima ou de baixo (e não apenas de cima), e não é tão sensível a uma semente mal escolhida (se a iteração de Newton fornecer uma semente que é muito baixa, será ultrapassar bastante o ponto de convergência e, em seguida, precisar voltar ao trabalho).

O método de Newton também tem o problema (pelo menos quando se lida com números inteiros) que muitas vezes atinge um x tal que A / x - x = 2 - nesse caso, converge para um valor um maior que a raiz inteira adequada, que precisa ser corrigido; O método de Halley não precisa dessa correção. Infelizmente, porém, o valor de 3*A + x*xgeralmente será maior que o espaço inteiro permitido de 32 bits.

Existem vários outros algoritmos de enésima raiz generalizados , mas todos compartilham essa mesma característica:

x = x + x*(v - x**n)/(v*n)
x = (x*(n+1) - x**(n+1)/v)/n
x = ((n-2)*x + (4*v*x)/(v + x**n))/n
x = x*((n+2)*v + (n-2)*x**n)/(v + x**n)/n
x = ((n-2)*x + (n*x*v)/(v + (n-1)*x**n))/(n-1)
x = ((n-2)*x + x*((n*2-1)*v + x**n)/(v + (n*2-1)*x**n))/(n-1)

x = x + 2*x*(v - x**n)/(v + x**n)/n
x = x + x*31*(v - x**n)/(10*v + 21*x**n)/n
x = x + x*561*(v - x**n)/(181*v + 380*x**n)/n
x = x + x*1153*(v - x**n)/(372*v + 781*x**n)/n

etc. A maioria deles exibe convergência cúbica ou quadrática. Os quatro últimos fazem parte de uma série de iterações que convergem na convergência quártica. Mas, na prática, o método de Newton fornece o que você precisa com menos operações, a menos que você precise calcular muitas centenas de dígitos.

primo
fonte
Muito bom, mas falha para 4294967295. Quanto às regras, elas precisam ser rígidas para torná-lo interessante. Você pode argumentar que premissas exatas fazem o melhor desafio, mas, em última análise, é muito mais importante que as regras sejam claras e inequívocas do que exatamente o que elas permitem.
Aaaaaaaaaaaa 13/09/2013
Eu não acho que Halley teria valido a pena de qualquer maneira, de um palpite distante, ele melhorará um pouco menos que um fator de 3, Newton faz um pouco menos que um fator de 2. Da mesma forma, de um bom palpite, Halley triplicará a precisão, Newton dobrará. Portanto, uma iteração Halley vale exatamente as log(3)/log(2) ~= 1.585iterações de Newton.
Aaaaaaaaaaaa 13/09/2013
@eBusiness Inicialmente, eu tinha 2 Halley's com uma semente escolhida da mesma forma, totalizando 25 ops - com erro quando A = 0- então isso é de fato mais curto. Cerca de 4294967295 , que foi uma supervisão: como 65536² ≡ 0 , a iteração da correção falha ao corrigir. Vou ver se consigo encontrar uma alternativa.
primo
@eBusiness corrigido.
primo
Raiz quadrada mais elegante do pacote, bom trabalho e um distintivo de vitória oficial.
Aaaaaaaaaaaa 20/09/2013
5

65 (61) operações (5 + 13 + 47 (43))

Tarefa 1 - Máx. (A, B)

RESULT = A + (B - A) * (A <= B)

Esta é a solução óbvia. Você precisa da atribuição, precisa de comparação, precisa multiplicar a comparação por algo, o multiplicando não pode ser uma das variáveis ​​e o produto não pode ser o resultado.

Tarefa 2 - Média (A, B, C)

RESULT = A                               \
       + (B - A) * (A > B) ^ (B <= C)    \
       + (C - A) * (A > C) ^ (C <  B)

Essa é uma melhoria em relação à minha solução anterior de 15 operações, que condicionou todas as três variáveis ​​- isso salvou duas subtrações, mas introduziu outro teste de centralidade. O teste em si é simples: um elemento está no meio, se exatamente um dos outros estiver acima.

Tarefa 3 - sqrt (A)

X1     = 1024 + A / 2048
X2     = (X1  + A / X1 ) / 2
...
X10    = (X9 + A / X9 ) / 2
RESULT = X16 - (X16 * X16 > A)

Onze rodadas de aproximação de Newton. A constante mágica de 1024 já é superada pelo WolframW (e 512 causa divisão por zero para a = 0 antes de a = 2 ** 32 convergir), mas se pudermos definir 0/0 como zero, dez iterações funcionarão com o valor inicial de 512. Eu admito que minha reivindicação de dez iterações não é totalmente clara, mas ainda as reivindico entre parênteses. Vou ter que investigar se nove é possível, no entanto.A solução do WolframH são nove iterações.

John Dvorak
fonte
Eu acho que a primeira linha da Tarefa 3 não está correta: a segunda constante deve ser 4 vezes a primeira constante (para ter Newton "puro").
Restabeleça Monica
@WolframH Um palpite inicial melhor pode explicar por que estou desperdiçando ciclos. Onde você criou 4 *? Parece duas iterações reunidas em uma.
John Dvorak
(1024 + A/1024)/2 == (512 + A/2048)(que é como X0 = 1024, e depois iniciar Newton).
Restabeleça Monica
Ótima solução para a Tarefa 1. Ovo de Colombo.
12133 DavidC
@DavidCarraher é claro, a solução correta seria MOV RESULT, A; CMP A,B; CMOVA RESULT, B;-)
John Dvorak
5

1: 5 operadores

RESULT = B ^ (A ^ B)*(A > B)

2: 13 operadores

RESULT = B ^ (A ^ B)*(A > B) ^ (A ^ C)*(A > C) ^ (B ^ C)*(B > C)

3: 27 operadores

g = 47|((0x00ffffff & A)>>10)|(A>>14)
r = (g + A/g)/3
r = (r + A/r)>>1
r = (r + A/r)>>1
r = (r + A/r)>>1
RESULT = r - (r*r-1>=A)
aaaaaaaaaaaa
fonte
5

Tarefa 3, 39 Operações

EDIT: última linha alterada; Ver comentários.

Esta é uma implementação do método Newthon. Testado com todos os quadrados positivos, e também com os quadrados positivos menos um e também um milhão de números aleatórios no intervalo de 0 a 2 ^ 32-1. O valor aparentemente engraçado começando é curto para (1022 + A/1022) / 2que precisa do mínimo número de iterações (eu acho), e também faz o RESULTpara A=0a direita (o que não seria o caso de 1024, em vez de 1022).

r = (511 + A/2044)
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
r = (r + A/r) / 2
RESULT = r - (r > A/r)
Restabelecer Monica
fonte
Devo manter minha cópia inferior do método de newton otimizada em paralelo à sua e postada um período decente mais tarde? Grandes mentes pensam da mesma forma e ter a solução dividida em duas duas respostas é ruim, mas é isso que está no estado atual, pois você não respondeu a # 2.
John Dvorak
@ JanDvorak: Obrigado por perguntar. Tudo bem se você colocar meu método um pouco mais curto em sua resposta. Além disso, obrigado por me dar crédito :-)
Reinstate Monica
Realmente boa tentativa, mas não para a entrada 4294965360 a 4294967295.
aaaaaaaaaaaa
@eBusiness: Que resultado você obtém para esses insumos? Recebo 65535 nos meus testes, o que é bom.
Restabeleça Monica
Recebo 65536. Talvez você não use o formato inteiro prescrito.
Aaaaaaaaaaaa 13/09