Implementar los operadores binarios de INTERCAL

29

El lenguaje del compilador sin acrónimo pronunciable, abreviado INTERCAL , es un lenguaje de programación muy exclusivo. Entre sus cualidades irreproducibles están sus operadores binarios.

Los dos operadores binarios de INTERCAL son intercalar (también conocido como mingle ) y select . Intercalar se representa con un cambio (¢), y seleccionar se representa con un sqiggle (~).

Interleave funciona tomando dos números en el rango 0-65535 y alternando sus bits. Por ejemplo:

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

Select funciona tomando dos números en el rango 0-65535, tomando los bits en el primer operando que están en la misma posición que 1s en el segundo operando, y colocando esos bits a la derecha.

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

En este desafío, se le dará una expresión binaria utilizando la operación intercalar o seleccionar. Debe calcular el resultado, utilizando la menor cantidad de bytes posible.

La expresión se dará como una cadena separada por espacios, que consta de un número entero en 0-65535, un espacio, uno ¢u ~otro, y un número entero en 0-65535.

La entrada y salida pueden realizarse a través de cualquier sistema estándar (STDIN, función, línea de comando, etc.). Lagunas estándar prohibidas.

Ejemplos:

5 ¢ 6
54

5 ~ 6
2

51234 ¢ 60003
4106492941

51234 ~ 60003
422

Este es el código de golf: menos bytes gana. Buena suerte.

EDITAR: Dado que algunos idiomas no admiten el símbolo de cambio (¢) de INTERCAL, puede utilizar el símbolo de dinero grande ($) en su lugar, con una penalización de 5 bytes.

isaacg
fuente
10
Es un poco duro penalizar a las personas por el uso del signo de dólar. Eso es algo que no se puede evitar.
Decaimiento Beta
9
Me acabo de dar cuenta de que CLWNPA es perfectamente pronouncable en galés. La W se pronuncia como U en español u OO en inglés.
Level River St
9
No obtengo la penalización de 5 bytes. C-INTERCAL utiliza el $.
kirbyfan64sos
13
¿De qué están discutiendo? Un $ es claramente más caro que un ¢. ¿Qué, quieres 99 ¢ por nada?
Max
66
No pensé que INTERCAL le permitiría ingresar números con números decimales. ¿No tienes que escribir FIVE ONE TWO THREE FOUR? ¿Y no debería ser la salida en números romanos?
Nate Eldredge

Respuestas:

9

Pyth, 32 31 29 bytes

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

Pruébelo en línea: Regular Input / Test Suite

Gracias a @isaacg por jugar golf en un byte.

Explicación:

                         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
fuente
Puede guardar un byte cambiando hMfeTa smmFdy luego mover el duplicado sfuera del ternario. Además, su código actual es de 32 bytes, no 33.
isaacg
@isaacg Wow. Nunca hubiera pensado en ese golf inteligente. Gracias. Y sí, hice un golf de último minuto mientras escribía la explicación y no actualicé el recuento de bytes.
Jakube
2
Es realmente interesante ver las respuestas de Pyth y CJam, casi siempre el mismo número de bytes, pero Pyth a menudo vence a CJam por unos pocos
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))

La cadena en la segunda línea contiene un único carácter no imprimible \x7d, el siguiente carácter después ~.

Todas las esperanzas de una bonita y única lambda quedan aplastadas por el formato de entrada. Probablemente haya una mejor manera de leer en la entrada. Entrada como a "51234 ¢ 60003"través de STDIN.

La función fcombina las siguientes dos funciones recursivas:

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 con la ayuda de @xnor)

Sp3000
fuente
1
+1 por la primera respuesta de Python realmente competitiva. Me preguntaba por qué te molestaste con la lambda y no solo usaste una expresión, sino que parece que hay cierta recurrencia allí. No sé Python, espero una explicación.
Level River St
Un poco de gran golpe! Estoy mirando la compresión del término constante expresión. La expresión (a%2*2+b%2)/3**dguarda 3 caracteres pero usa el complemento d=1-c. ¿Tienes una manera de hacer -~(3*c|b%2)con el complemento? En el peor, pierde 2 caracteres con 3-3*d. Además, el formato and-~x+ypuede ser andy-~xtan largo como ycomienza con un símbolo o número.
xnor
@xnor Entendido, (b%2+5&4-d). ¡Gracias!
Sp3000
11

CJam, 31 bytes

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

Pruébelo en línea en el intérprete de CJam .

Cómo 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
fuente
8

JavaScript (ES6), 103 117 119 124

Edite ahora trabajando con números en lugar de cadenas

(sin contar espacios iniciales, líneas nuevas y comentarios)

Pruebe a ejecutar el fragmento en cualquier navegador compatible con EcmaScript 6 (en particular, no Chrome ni MSIE. Probé en Firefox, Safari 9 podría funcionar)

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
fuente
5

Matlab, 119113 bytes

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

Sin golf:

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

Ejemplos:

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

>> f('2345 ~ 7245')
ans =
    37
Luis Mendo
fuente
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 + explicación:

# 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.
fuente
5

Python 3, 174 166 148 126

Bastante sencillo, operaciones de cadena, luego conversión a entero.

Limitado a números que en binario tienen 99 dígitos (máximo 2 ^ 99-1 = 633825300114114700748351602687).

Gracias, Sp3000 y 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))

O 165 caracteres, sin límite:

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))

Sin golf:

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
fuente
2
Puede usar en zfilllugar de rjust
rellenar
Entradas máximas a 16 bits y salidas a 32 bits. 99 bits es más que suficiente.
isaacg
Lo sé, pero como '99' toma tantos caracteres como '16', no hay beneficio de limitarlo.
Trang Oul
1
Unos pocos más: 1) No es necesario para salvar a,b, sólo hay que poner en el zipcon un *splat, 2) (i if j=='1'else'') -> i[:j>'0']3) Se puede utilizar este truco para ahorrar en la otraif/else
SP3000
1
Mi solución terminó siendo demasiado cercana a la suya, así que aquí es lo más breve que pude obtener la suya (126 bytes).
Kade
4

Pyth, 43 bytes

Una parte de mí se siente nerviosa al publicar una respuesta tan larga de Pyth a la pregunta de Isaac ...: oP

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

Explicación:

                                               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
fuente
44
¡Me encanta tu foto de perfil! :)
kirbyfan64sos
2
@ Kirbyfan64sos Blue Kirby es el mejor Kirby: o)
Sok
3

C, 127 123 bytes + 5 penalizaciones = 128

scanfcuenta el símbolo Unicode como más de un carácter que complica mucho las cosas, por lo que estoy aplicando la penalización de 5 bytes por usar $.

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

Los cambios de la versión original son:

-La prueba de $ o ~ ha sido revisada de q&2a q%7. Esto invierte los valores verdadero / falso, permitiendo que el código para el operador $ vaya antes del :que significa que se puede eliminar un conjunto de paréntesis.

-El iciclo ahora cuenta regresivamente en potencias de 2, que es más largo, pero permite >>ser sustituido por/ y guarda algunos paréntesis.

Versión 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 con un solo bucle con los condicionales dentro para evitar la sobrecarga de dos bucles. En ambos casos, desplazo los bits de los operandos hacia abajo hasta el bit del 1, y construyo el resultado del bit más significativo al menos significativo, desplazando a la izquierda el resultado (multiplicándolo por 2 o 4) a medida que avanzo.

Level River St
fuente
Lo jugué para ti: 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);} Intenté jugar al golf con las partes >> i & 1, pero no pude encontrar una manera rentable de hacerlo. Sin embargo, pude guardar 1 carácter al poner las definiciones de variables en main. Nota: no probado.
LambdaBeta
@LamdaBeta gracias, no pude encontrar una macro para >> i & 1 pero logré jugarlo de otra manera. Poner las variables como argumentos de maincausas qse corrompe en mi máquina, lo cual es extraño. Espero que el verdadero problema sea con scanf, pero por eso los he dejado como declaraciones normales.
Level River St
No había pensado en eso. Tienes razón, q se corromperá. La razón es que, si bien aprendemos que main toma dos argumentos, el recuento de argumentos de línea de comandos y una matriz de argumentos en sí, la mayoría de los sistemas en realidad proporcionan un tercer argumento (típicamente llamado char * envp []) que describe el entorno del código se ejecuta en (otorgando acceso a EG: variables de entorno). Por lo tanto, el sistema puede asignar un tercer valor en main, esta vez el scanf es inocente.
LambdaBeta
@steveverill Creo que también puedes eliminar la penalización de 5 bytes. Acabo de probar su código (usando ALT + 155 para hacer ¢) y parece funcionar bien. :)
LambdaBeta
@LambdaBeta en realidad la experimentación muestra que es una combinación de ambos. Con la declaración normal qse garantiza que sea cero, pero con la declaración como parámetro de funciónq contiene basura de 32 bits. Eso no sería un problema si me asignaron un valor a q, pero scanfcon la "%c"única sobrescribe los bits menos significativos 8 de la basura, dejando el otro 24 sin definir. ¡Podría tener suerte con otro compilador!
Level River St
3

K5, 53 52 bytes

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

Versión de 53 bytes:

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

Todavía necesita un poco más de golf.

kirbyfan64sos
fuente
3

CJam, 61 50 46 41 34 bytes

Gracias @Dennis por señalar un campo de golf de 4 bytes.

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

Pruébalo en línea .

Andrea Biondo
fuente
1
]{}/Es un noop.
Dennis
1
@ Dennis Gracias. Probablemente debería dormir un poco ...
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

la entrada se da aplicando la entrada a las funciones / operadores ? y¢ define en el código (Haskell no puede definir un operador~ por razones técnicas).

básicamente funciona el viejo enfoque recursivo.

orgulloso Haskeller
fuente
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 una línea de entrada

Se espera que la entrada termine después de una nueva línea con EOF

protista
fuente
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')`)

Prueba:

;[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')`)

Prueba:

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

PD: la nueva línea se cuenta como 1 byte, ya que se puede reemplazar por ;.

Qwertiy
fuente
1
0x10000 == 65536 (guardar 2 caracteres)
edc65
@ edc65, he actualizado la respuesta.
Qwertiy
2
65536 | x para evitar ~~
edc65
Solo se permite la segunda versión: la entrada debe tener la forma de una cadena delimitada por espacios.
isaacg
@isaacg, ok. Pero no quiero eliminar el primero por razones 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))

La versión completa y explicativa se puede encontrar en mi pastebin .

Oliver Friedrich
fuente
Puede asignar algunos caracteres eliminando espacios alrededor del operador '==', antes de 'if' y pasando 'base' como argumento posicional.
Trang Oul
¡Gracias, eso y algunos otros han guardado 15 caracteres! pero la forma duplicada de formatear el retorno todavía es demasiado.
Oliver Friedrich
Además, ¿utiliza 4 espacios por sangría? Una (o pestaña) es suficiente.
Trang Oul
2
@BeowulfOF A menos que se especifique lo contrario, puede enviar un programa completo o una función. En general, lo que es más corto dependerá de la forma en que su idioma analice la entrada específica para el desafío (ruby es sorprendentemente torpe con los números de stdin, por ejemplo). También tiene dos formas posibles de salida: stdout o valor de retorno, que son aplicables a ambos (aunque los valores de retorno de los programas son raros).
Level River St
1
Parece que solo usa euna vez, ¿no puede simplemente en línea?
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"}]&

Evalúa una función anónima tomando la cadena como entrada. Saltos de línea añadidos para mayor claridad.

fy gconvertir a / desde la base 2. Rifflehace exactamente lo que se supone intercalar . Quería usar Selectpara seleccionar, pero Casesdesafortunadamente es mejor. La última línea es un poco engañosa; se cambian los espacios, ~que es el operador infijo de Mathematica, luego se evalúa la cadena.

jcai
fuente