Operações de bits imprudentes

16

Eu gosto de jogar golfe dc, mas às vezes fico frustrado porque dcnão tem operações bit a bit.

Desafio

Fornecer quatro funções nomeadas que implementam o equivalente das operações c bit a bit &, |, ~e ^(bit a bit AND, OR, NOT e XOR). Cada função aceita dois operandos ( ~usa apenas um) que são, pelo menos, números inteiros não assinados de 32 bits. Cada função retornará um número inteiro não assinado da mesma largura de bit que os operandos.

Restrição

Você só pode usar operações suportadas por dc. Esses são:

  • + - * / Adição, subtração, multiplicação e divisão aritmética
  • ~ módulo (ou divmod, se o seu idioma suportar)
  • ^ exponenciação
  • | exponenciação modular
  • v raiz quadrada
  • > >= == != <= < operadores padrão de igualdade / desigualdade
  • >> <<operadores de troca de bits. dcnão os possui, mas, como eles são implementados trivialmente em termos de divisão / multiplicação por potências de 2, então permitirei.

Estruturas de controle no dcmeu ser desajeitadamente construídas usando macros (recursivas) e (in) operações de igualdade. Você pode usar qualquer estrutura de controle interna que seu idioma tiver.

Você também pode usar operadores lógicos && || ! , mesmo que eles não estejam diretamente disponíveis no dc.

Você não deve usar os operadores bit a bit & , |, ~e ^ou quaisquer funções que trivialmente implementá-las.

Além disso, você não deve usar operadores ou funções integradas de conversão de cadeia de caracteres.


Considere também fornecer um programa de teste ou um trecho do compilador on-line (não incluído na pontuação do golfe) para ajudar a verificar sua resposta.

Trauma Digital
fonte
Podemos implementar uma função que usa a operação desejada como parâmetro? Além disso, podemos dividir por 2 como um substituto para deslocamento de bits?
Xnor
@xnor Você deve fornecer 4 funções públicas que implementam cada um dos quatro operadores. Você também pode ter métodos / funções comuns / auxiliares particulares chamados pelas quatro funções públicas, mas todos precisarão ser incluídos na pontuação do golfe.
Digital Trauma
7
@xnor Você e você só também deve implementar o operador xnor ;-)
Trauma Digital
Posso produzir uma lista de quatro funções anônimas?
Xnor
@MariaTidalTug Qual é a diferença efetiva entre retornar uma lista de quatro funções e selecionar e aplicar manualmente uma (como sugerido xnor) versus ter uma função que aceita o parâmetro de seleção e executa a própria seleção (como respondeu o wolfhammer)? Ambos parecem minar de maneira semelhante o ponto de ter quatro funções nomeadas, pois transferem o tamanho do código para o código do usuário. Eu diria até que o primeiro o prejudica mais, pois o código do usuário é provavelmente mais complexo nesse caso do que no último.
precisa saber é o seguinte

Respostas:

4

C, 134

O pré-processador C é muito divertido de abusar. Basicamente esta macro define as funções 3, a, o, e x, para and, ore, xorrespectivamente. A única diferença no algoritmo para essas operações é o critério para definir o bit no resultado.

noté a função 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 testador (demora muito, eu não gastei muito tempo otimizando, mas ele testa todos os casos de teste possíveis, além dos MAX_INT relacionados):

#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));
        }
    }
pseudonym117
fonte
11
oops. esqueci disso. consertou isso agora.
Pseudonym117
4

ised 76 bytes

O ised também não possui operações bit a bit - geralmente irritantes, mas agora bem-vindas, porque realmente precisamos implementá-las.

As funções serão armazenadas em slots de memória numerados (sem nomes detalhados).

Conversão de e para binário:

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

NÃO poderia ser, @1{:$6::{1-$5::x}:}mas obviamente é mais fácil subtrair:

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

OU:

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

E:

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

XOR:

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

Isso nos levaria a 156 bytes (com novas linhas e ponto e vírgula). Um código de teste seria apenas (NOT, OR, AND, XOR em sucessão, encontrado sob os nomes $ 1, $ 2, $ 3, $ 4):

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

Mas é claro que OR e NOT são tudo o que realmente precisamos e as coisas podem ser simplificadas:

@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:};

São 109 caracteres. Quando novas linhas e ponto e vírgula são ignorados, e com um pouco mais de golfe, temos 76 caracteres:

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

Nim (537) (490)

Nim Compiler 0.10.2

Eu tenho procurado uma razão para aprender nim, então aqui vamos nós.

Para o código de golfe, utilizei parâmetros variáveis ​​e retornos implícitos. Os parâmetros variáveis, de acordo com a documentação, são menos eficientes na pilha. Pessoalmente, acho os retornos implícitos mais difíceis de ler e provavelmente os usariam apenas em procedimentos triviais.

Quanto aos algoritmos, eles são bastante simples. Para todas as operações, exceto NOT, comparamos cada bit e os comparamos manualmente com nossa tabela de verdade esperada. Defina cada bit conforme necessário ao longo do caminho em nossa variável de saída. Em Nim, resultado é o valor de retorno implícito.

Eu não tinha certeza se poderíamos usar OR e AND integrados para afirmar duas condições booleanas, de modo que o procedimento notZero foi colocado no lugar deles.

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)

Ainda procurando um método melhor ...

Aqui está a versão não esmagada e o equipamento de teste completo para rodar em sua própria máquina.
Se você deseja apenas executar algumas entradas, aqui está o caso de teste .

cory.todd
fonte
@MariaTidalTug obrigado por esclarecer!
Corint.todd
Eu não posso reproduzir isso. A sua calculadora está no modo base 16?
precisa saber é o seguinte
Adicionei um equipamento de teste semelhante ao pseudônimo117.
Corint.todd
1

CJam, 71 bytes

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

Explicação

"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.";

Suíte de teste

Esse código testa a execução de cada uma das minhas funções, e, ou, não, e xor 100 vezes com entradas não assinadas de 64 bits distribuídas uniformemente e compara o resultado com o produzido pelo operador interno. Devido ao uso gratuito do operador eval, é bastante lento e pode levar até um minuto com o intérprete online. Mas se tudo correr bem, a execução deve terminar sem saída, porque quaisquer discrepâncias encontradas são impressas.

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
fonte
0

Javascript 294 267

Conseguiu cortar mais alguns bytes com as sugestões de @ AlexA. E @ kennytm.

Funções:

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

exemplo:

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

resultado:

44, 44
300, 300
256, 256
4294966995, 4294966995
4294967039, 4294967039
martelo de lobo
fonte
2
Você precisa fornecer quatro funções públicas - uma para AND, OR. NÃO e XOR. (Você também pode ter métodos / funções particulares comuns / auxiliares chamadas pelas quatro funções públicas). Além disso, você está perdendo o NÃO - provavelmente o mais fácil de todos
Digital Trauma
Obrigado @AlexA. Eu adicionei os bytes e joguei um pouco mais.
wolfhammer
Você pode perder o espaço depois fore substituí-lo function B(n,m,t)por B=(n,m,t)=>. Da mesma forma para as outras funções.
Alex A.
① Você pode usar 4*(1<<30)para 4294967296 e -1>>>04294967295. ② é varrealmente necessário aqui? ③ você poderia escrever em (n,m)=>B(n,m,'a')vez de(n,m)=>{return B(n,m,'a')}
kennytm 04/04