Operaciones poco bitizadas

16

Me gusta jugar golf dc, pero a veces estoy frustrado porque dcno tiene operaciones bit a bit.

Desafío

Proporcionar cuatro funciones con nombre que implementan el equivalente de las operaciones c bit a bit &, |, ~y ^(bitwise AND, OR, NOT y XOR). Cada función tomará dos operandos ( ~toma solo uno) que son al menos enteros sin signo de 32 bits. Cada función devolverá un entero sin signo del mismo ancho de bits que los operandos.

Restricción

Solo puede usar operaciones compatibles con dc. Estos son:

  • + - * / Suma, resta, multiplicación y división aritmética
  • ~ módulo (o divmod si su idioma lo admite)
  • ^ exponenciación
  • | exponenciación modular
  • v raíz cuadrada
  • > >= == != <= < operadores estándar de igualdad / desigualdad
  • >> <<operadores de desplazamiento de bits. dcno tiene estos, pero dado que se implementan trivialmente en términos de división / multiplicación por potencias de 2, entonces permitiré estos.

Las estructuras de control en dcmi se pueden construir torpemente usando macros (recursivas) y operaciones de (in) igualdad. Puede usar cualquier estructura de control incorporada que tenga su idioma.

También puede usar operadores lógicos && || ! , aunque estos no estén disponibles directamente en dc.

Usted no debe utilizar los operadores bit a bit & , |, ~y ^o las funciones que implementan trivialmente ellos.

Además, no debe utilizar operadores o funciones integrados de conversión de cadenas de base.


También considere proporcionar un programa de prueba o un fragmento de compilador en línea (no incluido en el puntaje de golf) para ayudar a verificar su respuesta.

Trauma digital
fuente
¿Podemos implementar una función que tome la operación deseada como parámetro? Además, ¿podemos dividir enteros por 2 como sustituto para el desplazamiento de bits?
xnor
@xnor Debe proporcionar 4 funciones públicas que implementen cada uno de los cuatro operadores. También puede tener métodos / funciones privadas comunes / auxiliares que son llamadas por las cuatro funciones públicas, pero todas ellas deberán incluirse en el puntaje de golf.
Trauma digital
77
@xnor Usted y usted solo deben implementar el operador xnor ;-)
Digital Trauma
¿Puedo producir una lista de cuatro funciones anónimas?
xnor
@MariaTidalTug ¿Cuál es la diferencia efectiva entre devolver una lista de cuatro funciones y seleccionar y aplicar manualmente una (como sugirió xnor) versus tener una función que acepte el parámetro de selección y realice la selección en sí (como respondió Wolfhammer)? Ambos parecen socavar de manera similar el punto de tener cuatro funciones con nombre, ya que descargan el tamaño del código en el código del usuario. Incluso argumentaría que el primero lo socava más, ya que el código de usuario es probablemente más complejo en ese caso que en el último caso.
Runer112

Respuestas:

4

C, 134

El preprocesador C es bastante divertido de abusar. Básicamente esta macro define las 3 funciones, a, o, y x, por and, ory xorrespectivamente. La única diferencia en el algoritmo para estas operaciones es el criterio para establecer el bit en el resultado.

notEs la función n.

#define f(n,c)n(a,b){for(r=0,i=31;i+1;--i)if(((a>>i)%2+(b>>i)%2)c)r+=1<<i;return r;}
i,r;n(a){return 0xffffffff-a;}f(a,/2)f(o,)f(x,%2)

Programa de prueba (lleva mucho tiempo, no pasé ningún tiempo optimizándolo en absoluto, pero prueba todos los casos de prueba posibles, además de los relacionados con MAX_INT):

#define m_assert(expected, condition, actual)\
    if(!((expected) condition (actual)))\
        printf("assert fail @ line %i, expected: %x, actual %x, condition "#condition"\n", __LINE__, expected, actual);

int main()  {
    unsigned int j,k;
    for(j=0; j<0xffff; ++j)    {
        m_assert(~j, ==, n(j));
        for(k=0; k<0xffff; ++k)    {
            m_assert(j & k, ==, a(j,k));
            m_assert(j | k, ==, o(j,k));
            m_assert(j ^ k, ==, x(j,k));
        }
    }
seudónimo117
fuente
1
¡Uy! se olvidó de eso. arreglado eso ahora.
seudónimo117
4

ised 76 bytes

ised tampoco tiene operaciones bit a bit, generalmente molestas, pero ahora bienvenidas, porque realmente necesitamos implementarlas.

Las funciones se almacenarán en ranuras de memoria numeradas (sin nombres detallados).

Conversión ay desde binario:

@5{:x/2^[32]%2:};
@6{:x@:2^[32]:};

NO podría ser, @1{:$6::{1-$5::x}:}pero obviamente es más fácil restar:

@1{:2^32-x-1:};

O:

@2{:$6::{$5::{x_0}:+$5::{x_1}>0}:};

Y:

@3{:$6::{$5::{x_0}:*$5::{x_1}}:};

XOR:

@4{:$6::{$5::{x_0}:<>$5::{x_1}}:};

Esto nos llevaría a 156 bytes (con líneas nuevas y punto y coma). Un código de prueba simplemente sería (NOT, OR, AND, XOR en sucesión, encontrado bajo los nombres $ 1, $ 2, $ 3, $ 4):

> $1::{6}
4294967289
> $2::{12 11}
15
> $3::{12 11}
8
> $4::{12 11}
7

Pero, por supuesto, OR y NOT son todo lo que realmente necesitamos y las cosas se pueden simplificar:

@1{:2^32-x-1:};
@2{:@+{2^U{?{$5::x}%32}}:};
@3{:${1 2 1}::x:};
@4{:$3::{$2::x${1 2}::x}:};
@5{:x/2^[32]%2:};

Eso es 109 caracteres. Cuando se saltan las líneas nuevas y los puntos y comas, y con un poco más de golf, tenemos 76 caracteres:

@3{@1{:2^32-x-1:}@2{:@+{2^U{?{x/2^[32]%2}%32}}:}$1}@4{{:$2::x${1 2}::x:}$3};
Orión
fuente
1

Nim (537) (490)

Nim Compiler 0.10.2

He estado buscando una razón para aprender nim, así que aquí vamos.

Para el golf de código, he aprovechado parámetros variables y retornos implícitos. Los parámetros variables, según la documentación, son menos eficientes en la pila. Personalmente, encuentro que los retornos implícitos son más difíciles de leer y probablemente solo los usaría en procedimientos triviales.

En cuanto a los algoritmos, son lo suficientemente simples. Para todas las operaciones, excepto NOT, comparamos cada bit y los comparamos manualmente con nuestra tabla de verdad esperada. Establezca cada bit según sea necesario en nuestra variable de salida. En Nim, el resultado es el valor de retorno implícito.

No estaba seguro de si se nos permitía usar OR y AND integrados para afirmar dos condiciones booleanas, por lo que el procedimiento notZero se puso en su lugar.

proc s(x, y, b: var int)=
  x = x div 2
  y = y div 2
  b *= 2

proc n(x: var int): int =
  return -(x+1)

proc a(x, y: var int): int =
  var b = 1
  while x > 0 and y > 0:
    if (x mod 2  + y mod 2) == 2:
      result += b

    s(x,y,b)

proc o(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) >= 1:
      result += b

    s(x,y,b)

proc r(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) == 1:
      result += b

    s(x,y,b)

Todavía estoy buscando un mejor método ...

Aquí está la versión no aplastada más el arnés de prueba completo para ejecutar en su propia máquina.
Si solo desea ejecutar un par de entradas, aquí está el caso de prueba lite .

cory.todd
fuente
@MariaTidalTug gracias por aclarar!
cory.todd
No puedo reproducir eso. ¿Está su calculadora en modo base 16?
cory.todd
Agregué un arnés de prueba similar a pseudonym117.
cory.todd
1

CJam, 71 bytes

{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];

Explicación

"B : UInt64 UInt64 String -> UInt64
 Computes a bitwise operation on the two given unsigned integers. The operation
 is defined by the logical inverse of the result of evaluating the given string
 given the sum of two input bits.";
{
  :F;             "Save the operation string.";
  0               "Initialize the result to 0.";
  {               "For I from 0 through 63:";
    :R;             "Save the result.";
    2md@2md@        "Divide each input by 2 and collect the remainders as the
                     next pair of bits to process.";
    +F~!            "Compute the logical inverse of the result of evaluating
                     the operation string given the sum of the two bits.";
    2I#*            "Adjust the resulting bit to be in the correct output
                     position by multiplying it by 2^I.";
    R+              "Add the location-adjusted bit to the result.";
  }64fI
  \;\;            "Clean up.";
}:B

"A : UInt64 UInt64 -> UInt64
 Computes the bitwise AND of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 2)";
{"2-"B}:A

"O : UInt64 UInt64 -> UInt64
 Computes the bitwise OR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !(!(bit_in_1 + bit_in_2))";
{'!B}:O

"N : UInt64 -> UInt64
 Computes the bitwise NOT of the given unsigned integer.
 This is done by passing the input and 0 along to B with an operation such that:
   bit_out = !((bit_in + 0))";
{0SB}:N

"X : UInt64 UInt64 -> UInt64
 Computes the bitwise XOR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 1)";
{'(B}:X

];              "Clean up.";

Banco de pruebas

Este código prueba ejecuciones de cada una de mis funciones my and or or not y xor 100 veces con entradas sin signo distribuidas uniformemente de 64 bits y compara el resultado con el producido por el operador incorporado. Debido al uso gratuito del operador eval, es bastante lento y puede tomar hasta aproximadamente un minuto con el intérprete en línea. Pero si todo va bien, la ejecución debería terminar sin salida, porque se imprimen las discrepancias encontradas.

N:L;
{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];
{;Y32#__mr*\mr+}2e2%2/{~:U;:V;"A&O|X^"2/{[{US@SV" = "UV5$~L}/9$2$={];}{]oLo}?}/"N~"[{U" = "U3$~Y64#(&L}/6$2$={];}{]oLo}?}/
Runer112
fuente
0

JavaScript 294 267

Pude reducir algunos bytes más con las sugerencias de @ AlexA. y @ kennytm.

Funciones:

B=(n,m,t)=>{for(var p=4294967296,y=0;p>=1;p/=2)y+=t=='x'&&(n>=p||m>=p)&& !(n>=p&&m>=p)?p:0,y+=t=='a'&&n>=p&&m>=p?p:0,y+=t=='o'&&(n>=p||m>=p)?p:0,n-=n>=p?p:0,m-=m>=p?p:0
return y}
N=(n)=>{return 4294967295-n}
A=(n,m)=>B(n,m,'a')
O=(n,m)=>B(n,m,'o')
X=(n,m)=>B(n,m,'x')

ejemplo:

var n = 300;
var m = 256;
console.log(X(n,m) + ", " + (n ^ m));
console.log(O(n,m) + ", " + (n | m));
console.log(A(n,m) + ", " + (n & m));
console.log(N(n) + ", " + (~n>>>0));
console.log(N(m) + ", " + (~m>>>0));

salida:

44, 44
300, 300
256, 256
4294966995, 4294966995
4294967039, 4294967039
martillo de lobo
fuente
2
Debe proporcionar cuatro funciones públicas, una para AND, OR. NO y XOR. (También puede tener métodos / funciones privadas comunes / auxiliares que son llamadas por las cuatro funciones públicas). Además, se echa en falta la NO - probablemente el más fácil de todos ellos para hacerlo
Digital Trauma
Gracias @AlexA. Agregué los bytes y lo jugué un poco más.
wolfhammer
Puede perder el espacio después fory reemplazarlo function B(n,m,t)con B=(n,m,t)=>. Del mismo modo para las otras funciones.
Alex A.
① Podría usar 4*(1<<30)para 4294967296 y -1>>>0para 4294967295.. ¿Es varrealmente necesario aquí? ③ podrías escribir en (n,m)=>B(n,m,'a')lugar de(n,m)=>{return B(n,m,'a')}
kennytm