Implementar operadores binários da INTERCAL

29

A linguagem do compilador sem acrônimo pronunciável, abreviado INTERCAL , é uma linguagem de programação muito exclusiva. Entre suas qualidades improdutíveis estão seus operadores binários.

Os dois operadores binários da INTERCAL são intercalados (também conhecidos como misturar ) e selecionados . A intercalação é representada com uma alteração (¢) e a seleção é representada com um quadrado (~).

A intercalação funciona tomando dois números no intervalo de 0 a 65535 e alternando seus bits. Por exemplo:

234 ¢ 4321
234   = 0000011101010
4321  = 1000011100001
Result: 01000000001111110010001001
Output: 16841865

Selecione trabalhos, pegando dois números no intervalo de 0 a 65535, pegando os bits no primeiro operando que estão na mesma posição que 1s no segundo operando e colocando esses bits à direita.

2345 ~ 7245
2345  = 0100100101001
7245  = 1110001001101
Taken : 010   0  10 1
Result: 0100101
Output: 37

Nesse desafio, você receberá uma expressão binária usando a operação intercalar ou selecionar. Você deve calcular o resultado usando o menor número possível de bytes.

A expressão será dada como uma sequência separada por espaço, consistindo em um número inteiro em 0-65535, um espaço em um ¢ou em ~um espaço e um número inteiro em 0-65535.

A entrada e a saída podem ser feitas através de qualquer sistema padrão (STDIN, função, linha de comando, etc.). Falhas padrão proibidas.

Exemplos:

5 ¢ 6
54

5 ~ 6
2

51234 ¢ 60003
4106492941

51234 ~ 60003
422

Este é o código golf - o menor número de bytes vence. Boa sorte.

EDIT: Como alguns idiomas não suportam o símbolo de alteração (¢) da INTERCAL, você pode usar o símbolo de muito dinheiro ($), com uma penalidade de 5 bytes.

isaacg
fonte
10
É um pouco severo penalizar as pessoas pelo uso do cifrão. Isso é algo que não pode ser ajudado.
Decay Beta
9
Acabei de perceber que o CLWNPA é perfeitamente pronunciável em galês. OW é pronunciado como U em espanhol ou OO em inglês.
Level River St
9
Eu não recebo a penalidade de 5 bytes. C-INTERCAL usa o $.
kirbyfan64sos
13
O que vocês estão discutindo? Um $ é claramente mais caro que um ¢. Você quer 99 centavos por nada?
Max
6
Não achei que INTERCAL permitisse inserir números com números decimais. Você não tem que escrever FIVE ONE TWO THREE FOUR? E a saída não deveria estar em algarismos romanos?
Nate Eldredge

Respostas:

9

Pitão, 32 31 29 bytes

isummFdG}\~zCm.[Z16jvd2%2cz)2

Experimente on-line: Conjunto regular de entrada / teste

Obrigado a @isaacg por jogar fora um byte.

Explicação:

                         cz)   split input at spaces
                       %2      only take every second item (the numbers)
             m                 map each number d to:
                    vd           convert d to int
                   j  2          convert to base 2
              .[Z16              pad zeros at the left
            C                  zip
  u     }\~z                   apply the following function ("~" in input) times:
   m   G                         map each pair d to:
    mFd                          convert [x,0] to [] and [x,1] to [x]
 s                             take sum (unfold all lists)
i                           2  convert back from base 2 and print
Jakube
fonte
Você pode salvar um byte, alterando hMfeTpara smmFde movendo a duplicata para sfora do ternário. Além disso, o código atual é de 32 bytes, e não 33.
isaacg
@isaacg Wow. Eu nunca teria pensado naquele golfe inteligente. Obrigado. E sim, jogou golfe de última hora enquanto escrevia a explicação e não atualizava a contagem de bytes.
Jakube 10/08/15
2
É realmente interessante ver Pyth e CJam respostas, quase sempre a mesma contagem de bytes, mas Pyth muitas vezes bate CJam por alguns
Kametrixom
13

Python 2, 115 112 bytes

x,y,z=input().split()
d=y<""
f=lambda a,b:a+b and(b%2+5&4-d)*f(a/2,b/2)+(a%2*2+b%2)/3**d
print f(int(x),int(z))

A sequência na segunda linha contém um único caractere não imprimível \x7d, o próximo caractere a seguir ~.

Todas as esperanças de um lambda único e agradável são esmagadas pelo formato de entrada. Provavelmente existe uma maneira melhor de ler as entradas. Entrada como "51234 ¢ 60003"via STDIN.

A função fcombina as duas funções recursivas a seguir:

g=lambda a,b:a+b and 4*g(a/2,b/2)+a%2*2+b%2    # ¢
h=lambda a,b:a+b and(b%2+1)*h(a/2,b/2)+a*b%2   # ~

(-3 bytes com a ajuda de @xnor)

Sp3000
fonte
11
+1 para a primeira resposta realmente competitiva do Python. Fiquei me perguntando por que você se incomodou com o lambda e não apenas usou uma expressão, mas parece que há alguma recursão lá? Eu não sei Python, estou ansioso por uma explicação.
Level River St
Alguma coisa incrível! Estou procurando comprimir o termo constante expressão. A expressão (a%2*2+b%2)/3**dsalva 3 caracteres, mas usa o complemento d=1-c. Você tem uma maneira de fazer -~(3*c|b%2)com o complemento? Na pior das hipóteses, perde 2 caracteres com 3-3*d. Além disso, o formato and-~x+ypode andy-~xdurar desde que ycomece com um símbolo ou número.
Xnor
@xnor Entendi (b%2+5&4-d). Obrigado!
Sp3000 12/08/2015
11

CJam, 31 bytes

rrc\r]{i2bF0e[}%(7=\zf{_)*?~}2b

Experimente on-line no intérprete CJam .

Como funciona

rr                              e# Read two tokens from STDIN.
  c\                            e# Cast the second to char and swap with the first.
    r                           e# Read a third token from STDIN.
     ]                          e# Wrap everything in an array.
      {       }%                e# For all three elements:
       i2b                      e#   Cast to int and convert to base 2.
          F0e[                  e#   Left-pad with zeroes to complete 15 digits.
                (               e# Shift out the first base 2 array.
                 7=             e# Select its eighth MSB (1 for '¢', 0 for '~').
                   \            e# Swap with the array of base 2 arrays.
                    z           e# Zip to transpose rows with columns.
                     f{     }   e# For each pair of base 2 digits:
                                e#   Push the bit, then the pair.
                       _        e#   Copy the pair.
                        )       e#   Pop the second digit.
                         *      e#   Repeat the first digit that many times.
                          ?     e#   Ternary if. Select the pair if the bit is
                                e#    truthy, the repeated first bit if it's falsy.
                           ~    e#   Dump the selected array on the stack.
                             2b e# Convert from base 2 to integer.
Dennis
fonte
8

JavaScript (ES6), 103 117 119 124

Editar agora trabalhando com números em vez de cadeias

(sem contar espaços iniciais, novas linhas e comentários)

Teste a execução do snippet em qualquer navegador compatível com EcmaScript 6 (principalmente o Chrome, não o MSIE. Eu testei no Firefox, o Safari 9 poderia ir)

I=s=>
  (i=>{
    for(m=r=0,[a,o,b]=s.split` `;i>0;i<<=1) // loop until bit 31 of i is set
      o>'~'?r+=(b&i)*i+(a&i)*2*i:b&i?r+=(a&i)>>m:++m
  })(1)||r


// TEST
out=x=>O.innerHTML+=x+'\n\n';

[ ['234 ¢ 4321', 16841865], ['2345 ~ 7245', 37]
, ['5 ¢ 6', 54], ['5 ~ 6', 2]
, ['51234 ¢ 60003',4106492941], ['51234 ~ 60003', 422]]
.forEach(([i,o,r=I(i)])=>{
  out('Test '+ (o==r?'OK':'Fail')+'\nInput:    '+ i+'\nResult:   '+r+'\nExpected: '+o)})
<pre id=O></pre>

edc65
fonte
5

Matlab, 119 113 bytes

function f(s)
t=dec2bin(str2double(strsplit(s,{'¢' '~'}))');u=any(s>'~');[~u u]*bin2dec({t(1,t(2,:)==49) t(:)'})

Ungolfed:

function f(s)                                     % input s is a string
t = dec2bin(str2double(strsplit(s,{'¢' '~'}))');  % get the two numbers and convert to
                                                  % two-row char array of zeros of ones
u = any(s>'~');                                   % 1 indicates '¢'; 0 indicates '~'
[~u u]*bin2dec({t(1,t(2,:)==49) t(:)'})           % compute both results and display
                                                  % that indicated by u

Exemplos:

>> f('234 ¢ 4321')
ans =
    16841865

>> f('2345 ~ 7245')
ans =
    37
Luis Mendo
fonte
5

R, 145 bytes

s=scan(,"");a=as.double(c(s[1],s[3]));i=intToBits;cat(packBits(if(s[2]=="~")c(i(a[1])[i(a[2])>0],i(0))[1:32] else c(rbind(i(a[2]),i(a[1]))),"i"))

Ungolfed + explicação:

# Read a string from STDIN and split it on spaces
s <- scan(, "")

# Convert the operands to numeric
a <- as.double(c(s[1], s[3]))

o <- if (s[2] == "~") {
    # Get the bits of the first operand corresponding to ones in
    # the second, right pad with zeros, and truncate to 32 bits
    c(intToBits(a[1])[intToBits(a[2]) == 1], intToBits(0))[1:32]
} else {
    # Interleave the arrays of bits of the operands
    c(rbind(intToBits(a[2]), intToBits(a[1])))
}

# Make an integer from the raw bits and print  it to STDOUT
cat(packBits(o, "integer"))
Alex A.
fonte
5

Python 3, 174 166 148 126 126

Operações simples e simples de string, depois conversão de volta para inteiro.

Limitado a números que em binário possuem 99 dígitos (máximo 2 ^ 99-1 = 633825300114114700748351602687).

Obrigado, Sp3000 e Vioz!

a,o,b=input().split()
print(int(''.join([(i+j,i[:j>'0'])[o>'~']for i,j in zip(*[bin(int(j))[2:].zfill(99)for j in(a,b)])]),2))

Ou 165 caracteres, sem limite:

a,o,b=input().split()
a,b=[bin(int(j))[2:]for j in(a,b)]
print(int(''.join([(i if j=='1'else'')if o=='~'else i+j for i,j in zip(a.zfill(len(b)),b.zfill(len(a)))]),2))

Ungolfed:

a, op, b = input().split()
a, b = [bin(int(j))[2:] for j in(a,b)] #convert to int (base 10), then to binary, remove leading '0b'
m = max(len(a), len(b))
a = a.zfill(m) #fill with leading zeroes
b = b.zfill(m)
if op == '~':
    ret = [i if j=='1' else'' for i, j in zip(a, b)]
else:
    ret = [i + j for i, j in zip(a, b)]
ret = ''.join(ret) #convert to string
ret = int(ret, 2) #convert to integer from base 2
print(ret)
Trang Oul
fonte
2
Você pode usar zfillem vez de rjustpara o preenchimento com zeros
SP3000
As entradas atingem no máximo 16 bits e as saídas 32 bits. 99 bits é mais que suficiente.
Isaacg
Eu sei, mas como '99' tem tantos caracteres quanto '16', não há benefício em limitá-lo.
Trang Oul
11
Um pouco mais: 1) Você não precisa salvar a,b, basta colocá-lo no zipcom um *splat, 2) (i if j=='1'else'') -> i[:j>'0']3) Você pode usar essa dica para salvar do outroif/else
Sp3000 10/15/15
11
Minha solução acabou sendo muito próxima da sua, então aqui está o mais curto possível para você (126 bytes).
Kade
4

Pitão, 43 bytes

Parte de mim se sente nervosa ao postar uma resposta Pyth tão longa na pergunta de isaacg ...: oP

J.(Kczd1Am.BvdKiu?qJ\~u+G?qeH\1hHk+VGHk.iGH2

Explicação:

                                               Implicit: z=input(), k='', d=' '
   Kczd                                        Split z on spaces, store in K
J.(    1                                       Remove centre element from K, store in J
         m    K                                For each d in K
          .Bvd                                 Evaluate as int, convert to binary string
        A                                      Store pair in G and H
                                               ~ processing:
                                 +VGH          Create vectorised pairs ([101, 110] -> [11, 01, 10])
                     u               k         Reduce this series, starting with empty string
                        ?qeH\1                 If 2nd digit == 1...
                              hHk              ... take the 1st digit, otherwise take ''
                      +G                       Concatenate
                                      .iGH     ¢ processing: interleave G with H
                ?qJ\~                          If J == ~, take ~ processing, otherwise take ¢
               i                          2    Convert from binary to decimal
Sok
fonte
4
Eu amo sua foto de perfil! :)
kirbyfan64sos
2
@ kirbyfan64sos Blue Kirby é o melhor Kirby: o) #
Sok
3

C, 127 123 bytes + 5 penalidade = 128

scanfconta o símbolo unicode como mais de um caractere, o que complica bastante as coisas, por isso estou aplicando a penalidade de 5 bytes pelo uso $.

a,b,q,x,i;main(){scanf("%d %c %d",&a,&q,&b);for(i=65536;i/=2;)q%7?x=x*4|a/i*2&2|b/i&1:b/i&1&&(x=x*2|a/i&1);printf("%u",x);}

As alterações da versão original são:

-O teste de $ ou ~ foi revisado de q&2para q%7. Isso inverte os valores verdadeiro / falso, permitindo que o código do operador $ vá antes do :que significa que um conjunto de parênteses pode ser eliminado.

-O iloop agora conta com potências de 2 maiores, mas permite >>ser substituído por /e salva alguns parênteses.

Versão original 127 bytes

a,b,q,x,i;
main(){
  scanf("%d %c %d",&a,&q,&b);
  for(i=16;i--;)
    q&2?
      b>>i&1&&(x=x*2|a>>i&1):    // ~ operator. && used as conditional: code after it is executed only if code before returns truthy.
      (x=x*4|(a>>i&1)*2|b>>i&1); // $ operator
  printf("%u",x);
}

Fui com um único loop com as condicionais dentro para evitar a sobrecarga de dois loops. Em ambos os casos, eu desloco os bits dos operandos para o bit 1 e constro o resultado do bit mais significativo para o menos significativo, mantendo o resultado à esquerda (multiplicando por 2 ou 4) à medida que for avançando.

Level River St
fonte
Joguei isso para você: main (a, b, q, x, i) {scanf ("% d% c% d", & a, & q, & b); for (i = 16; i -;) q & 2? b >> i & 1 && (x = x * 2 | a >> i & 1) :( x = x * 4 | (a >> i & 1) * 2 | b >> i & 1); printf ("% u", x);} Tentei jogar golfe nas partes >> i & 1, mas não consegui encontrar uma maneira econômica de fazê-lo. Consegui salvar 1 caractere, colocando as definições das variáveis ​​em principal. Nota: não testado.
LambdaBeta
@LamdaBeta obrigado, não consegui encontrar uma macro para >> i & 1, mas consegui jogar de outra maneira. Colocar as variáveis ​​como argumentos de maincausas qa serem corrompidas na minha máquina, o que é estranho. Eu espero que o problema real esteja com scanf, mas por causa disso eu os deixei como declarações normais.
Level River St
Eu não tinha pensado nisso. Você está certo, q será corrompido. A razão é que, enquanto aprendemos que main recebe dois argumentos, a contagem de argumentos da linha de comando e uma matriz dos próprios argumentos, a maioria dos sistemas fornece um terceiro argumento (geralmente chamado char * envp []) que descreve o ambiente em que o código é executado em (concedendo acesso a EG: variáveis ​​de ambiente). Assim, o terceiro valor em main também pode receber um valor do sistema, scanf é inocente dessa vez.
precisa saber é o seguinte
@everevill Acho que você também pode remover a penalidade de 5 bytes. Acabei de testar seu código (usando ALT + 155 para fazer ¢) e ele parece funcionar bem. :)
LambdaBeta
O @LambdaBeta, na verdade, a experimentação mostra que é uma combinação de ambos. Com a declaração normal qé garantido que seja zero, mas com a declaração como um parâmetro de função qcontém lixo de 32 bits. Isso não seria um problema se eu atribuído um valor a q, mas scanfcom "%c"única substitui os 8 bits menos significativos do lixo, deixando o outro 24 indefinido. Eu posso ter sorte com outro compilador!
Level River St
3

K5, 53 52 bytes

{b/({,/x,'y};{x@&y})[*"~"=y][b\.x;(b:20#2)\.z]}." "\

Versão de 53 bytes:

{b/({,/x,'y};{x@&y})[*"¢~"?y][b\.x;(b:20#2)\.z]}." "\

Ainda precisa de um pouco mais de golfe.

kirbyfan64sos
fonte
3

CJam, 61 50 46 41 34 bytes

Obrigado @Dennis por apontar um golfe de 4 bytes.

rrc'~=:X;r]{i2bF0e[}/.{X{{;}|}&}2b

Experimente online .

Andrea Biondo
fonte
11
]{}/é um noop.
Dennis
11
@ Dennis Obrigado. Provavelmente eu deveria dormir um pouco ...
Andrea Biondo
3

Haskell, 77

g=(`mod`2)
h=(`div`2)
0¢0=0
a¢b=g a+2*b¢h a
a?0=0
a?b=g a*g b+(1+g b)*h a?h b

A entrada é fornecida aplicando a entrada às funções / operadores ?e ¢definida no código (Haskell não pode definir um operador ~por razões técnicas).

basicamente funciona a antiga abordagem recursiva.

orgulhoso haskeller
fonte
2

J, 173

f=:|."1@(>@(|.&.>)@(#:@{:;#:@{.))
m=:2&#.@:,@:|:@:|.@:f
s=:2&#.@#/@:f
a=:{&a.@-.
(1!:2)&2(s@".@:a&126)^:(126 e.i)((m@".@:a&194 162)^:(1 e.194 162 E.i)i=._1}.(a.i.((1!:1)3)))

espera uma linha de entrada

entrada esperada para terminar após nova linha com EOF

protista
fonte
2

Javascript ES6 (3 argumentos) 141 138 136 121 119 bytes

b=x=>(65536|x).toString`2`
f=(x,o,y)=>+eval(`'0b'+(b(y)+b(x)).replace(/^1|${o=='~'?1:'(.)'}(?=.{16}(.)())|./g,'$2$1')`)

Teste:

;[f(234,'¢',4321),f(2345,'~',7245)]=="16841865,37"

Javascript ES6 (1 argumento) 135 133 bytes

b=x=>(65536|x).toString`2`
f=s=>([x,o,y]=s.split` `)|eval(`'0b'+(b(y)+b(x)).replace(/^1|${o=='~'?1:'(.)'}(?=.{16}(.)())|./g,'$2$1')`)

Teste:

;[f('234 ¢ 4321'),f('2345 ~ 7245')]=="16841865,37"

PS: A nova linha é contada como 1 byte, pois pode ser substituída por ;.

Qwertiy
fonte
11
0x10000 == 65536 (economize 2 caracteres)
edc65
@ edc65, atualizei a resposta.
Qwertiy
2
65536 | x Para evitar ~~
edc65
Somente a segunda versão é permitida - a entrada deve estar na forma de uma sequência delimitada por espaço.
Isaacg
@isaacg, ok. Mas não quero excluir o primeiro por razões históricas.
Qwertiy
2

Python 3, 157 bytes

a,x,y=input().split()
i=int
b=bin
print(i(''.join(([c for c,d in zip(b(i(a)),b(i(y)))if d=='1'],[c+d for c,d in zip(b(i(a))[2:],b(i(y))[2:])])['¢'==x]),2))

A versão completa e explicativa pode ser encontrada no meu pastebin .

Oliver Friedrich
fonte
Você pode definir alguns caracteres removendo espaços ao redor do operador '==', antes de 'if' e passando 'base' como argumento posicional.
Trang Oul
Obrigado, isso e alguns outros salvaram 15 caracteres! mas a maneira duplicada de formatar o retorno ainda é grande.
Oliver Friedrich
Além disso, você usa 4 espaços por travessão? Uma (ou guia) é suficiente.
Trang Oul
2
@BeowulfOF A menos que seja especificado de outra forma, você pode enviar um programa ou uma função completa. Geralmente, o que for mais curto, dependerá da maneira como o seu idioma analisa a entrada específica para o desafio (ruby é surpreendentemente desajeitado com números de stdin, por exemplo). Você também tem duas maneiras possíveis para a saída: stdout ou valor de retorno, que são aplicáveis a ambos (embora valores de retorno dos programas são raros.)
Nível River St
11
Você parece usar apenas euma vez, não pode simplesmente incorporá-lo?
Kevin Brown
0

Mathematica, 155 bytes

f=IntegerDigits[#,2,16]&;
g=#~FromDigits~2&;
¢=g[f@#~Riffle~f@#2]&;
s=g@Cases[Thread@{f@#,f@#2},{x_,1}->x]&;
ToExpression@StringReplace[#,{" "->"~","~"->"s"}]&

Avalia como uma função anônima, tendo a string como entrada. Quebras de linha adicionadas para maior clareza.

fe gconverter de / para a base 2. Rifflefaz exatamente o que a intercalação deve fazer. Eu queria usar Selectpara selecionar, mas Casesé melhor, infelizmente. A última linha é um pouco de truque; os espaços são alterados para ~o operador de infixo do Mathematica, a sequência é avaliada.

jcai
fonte