Operazioni bit poco sagge


16

Mi piace giocare a golf dc, ma a volte sono frustrato perché dcnon ha operazioni bit per bit.

Sfida

Fornire quattro funzioni denominate che implementano l'equivalente delle operazioni c bit per bit &, |, ~e ^(bit AND, OR, NOT e XOR). Ogni funzione prenderà due operandi (ne ~accetta solo uno) che sono numeri interi senza segno di almeno 32 bit. Ogni funzione restituirà un numero intero senza segno della stessa larghezza di bit degli operandi.

Restrizione

È possibile utilizzare solo operazioni supportate da dc. Questi sono:

  • + - * / Aggiunta, sottrazione, moltiplicazione e divisione aritmetica
  • ~ modulo (o divmod se la tua lingua lo supporta)
  • ^ elevamento a potenza
  • | esponenziazione modulare
  • v radice quadrata
  • > >= == != <= < operatori di uguaglianza / disuguaglianza standard
  • >> <<operatori bit shift. dcnon ha questi, ma dal momento che sono banalmente implementati in termini di divisione / moltiplicazione per potenze di 2, allora li permetterò.

Le strutture di controllo nel dcmio devono essere costruite goffamente usando macro (ricorsive) e operazioni (in) di uguaglianza. Puoi usare qualsiasi struttura di controllo integrata nella tua lingua.

È inoltre possibile utilizzare operatori logici && || ! , anche se questi non sono direttamente disponibili in dc.

È necessario non utilizzare gli operatori bit per bit & , |, ~e ^o qualsiasi funzioni che banalmente li implementano.

Inoltre, non è necessario utilizzare operatori o funzioni di conversione di stringhe di base incorporati.


Considera anche di fornire un programma di test o uno snippet di compilatore online (non incluso nel punteggio del golf) per verificare la tua risposta.


Possiamo implementare una funzione che accetta l'operazione desiderata come parametro? Inoltre, possiamo dividere l'intero per 2 come stand-in per bit-shift?
xnor

@xnor È necessario fornire 4 funzioni pubbliche che implementano ciascuno dei quattro operatori. Potresti anche avere metodi / funzioni private / helper private che sono chiamati da tutte e quattro le funzioni pubbliche, ma queste dovranno essere tutte incluse nel punteggio del golf.
Trauma digitale

7
@xnor Tu e tu devi solo implementare l'operatore xnor ;-)
Digital Trauma

Posso produrre un elenco di quattro funzioni anonime?
xnor

@MariaTidalTug Qual è la differenza effettiva tra la restituzione di un elenco di quattro funzioni e la selezione e l'applicazione manuale di una (come suggerito da xnor) rispetto alla presenza di una funzione che accetta il parametro di selezione ed esegue la selezione stessa (come rispose wolfhammer)? Entrambi sembrano minare allo stesso modo il punto di avere quattro funzioni nominate, mentre scaricano le dimensioni del codice sul codice utente. Direi anche che il primo lo mina di più, poiché il codice utente è probabilmente più complesso in quel caso che nel secondo caso.
Runer112,

Risposte:


4

C, 134

Il preprocessore C è piuttosto divertente da abusare. Fondamentalmente questa macro definisce le 3 funzioni, a, oe x, per and, ore xorrispettivamente. L'unica differenza nell'algoritmo per queste operazioni sono i criteri per impostare il bit nel risultato.

notè la funzione 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)

Programma Tester (richiede molto tempo, non ho impiegato molto tempo per ottimizzarlo, ma verifica tutti i casi di test possibili, oltre a quelli relativi a 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));
        }
    }

1
oops. dimenticato. risolto questo ora.
pseudonimo117,

4

76 byte

Inoltre non ha operazioni bit per bit - di solito fastidiose, ma ora benvenute, perché abbiamo davvero bisogno di implementarle.

Le funzioni saranno memorizzate in slot di memoria numerati (nessun nome dettagliato).

Conversione da e verso binario:

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

NOT potrebbe essere @1{:$6::{1-$5::x}:}ma è ovviamente più semplice sottrarre:

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

O:

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

Questo ci porterebbe a 156 byte (con newline e punti e virgola). Un codice di prova sarebbe semplicemente (NOT, OR, AND, XOR in successione, trovato sotto i nomi $ 1, $ 2, $ 3, $ 4):

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

Ma ovviamente OR e NOT sono tutto ciò di cui abbiamo veramente bisogno e le cose possono essere semplificate:

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

Sono 109 caratteri. Quando vengono saltati newline e punti e virgola e con un po 'più di golf, abbiamo 76 caratteri:

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

1

Nim (537) (490)

Compilatore Nim 0.10.2

Ho cercato un motivo per imparare NIM, quindi eccoci qui.

Per il golf del codice, ho sfruttato parametri variabili e rendimenti impliciti. I parametri variabili, secondo la documentazione, sono meno efficienti nello stack. Personalmente, trovo che i ritorni impliciti siano più difficili da leggere e probabilmente li userei solo in procedure banali.

Per quanto riguarda gli algoritmi, sono abbastanza semplici. Per tutte le operazioni tranne NOT, confrontiamo ogni bit e li confrontiamo manualmente con la nostra tabella di verità prevista. Impostare ogni bit secondo necessità lungo la strada nella nostra variabile di output. In Nim, risultato è il valore di ritorno implicito.

Non ero sicuro che ci fosse permesso di usare OR ed AND integrati per affermare due condizioni booleane, così la procedura notZero fu messa al loro posto.

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)

Stai ancora cercando un metodo migliore ...

Ecco la versione non schiacciata più il cablaggio di prova completo per l'esecuzione sulla propria macchina.
Se vuoi solo eseguire un paio di input, ecco il case test lite .


@MariaTidalTug grazie per il chiarimento!
cory.todd,

Non riesco a riprodurlo. La tua calcolatrice è in modalità base 16?
cory.todd,

Ho aggiunto un cablaggio di prova simile a quello dello pseudonimo117.
cory.todd,

1

CJam, 71 byte

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

Spiegazione

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

Suite di test

Questo codice verifica le esecuzioni di ciascuna delle mie funzioni my e, o, not e xor 100 volte con ingressi senza segno a 64 bit distribuiti uniformemente e confronta il risultato con quello prodotto dall'operatore integrato. A causa dell'uso gratuito dell'operatore eval, è piuttosto lento e può richiedere fino a circa un minuto con l'interprete online. Ma se tutto va bene, l'esecuzione dovrebbe terminare senza output, perché vengono stampate eventuali discrepanze.

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}?}/

0

JavaScript 294 267

È stato in grado di radere qualche byte in più con i suggerimenti di @ AlexA. e @ kennytm.

funzioni:

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

esempio:

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

produzione:

44, 44
300, 300
256, 256
4294966995, 4294966995
4294967039, 4294967039

2
È necessario fornire quattro funzioni pubbliche, una per ognuna per AND, OR. NOT e XOR. (Potresti anche avere metodi / funzioni private / helper private che sono chiamati da tutte e quattro le funzioni pubbliche). Inoltre, ti stai perdendo il NOT - probabilmente il più semplice di tutti questi da fare
Digital Trauma

Grazie @AlexA. Ho aggiunto i byte e l'ho ancora giocato a golf.
Wolfolfer,

Puoi perdere lo spazio dopo fore sostituirlo function B(n,m,t)con B=(n,m,t)=>. Allo stesso modo per le altre funzioni.
Alex A.

① È possibile utilizzare 4*(1<<30)per 4294967296 e -1>>>0per 4294967295. ② è ilvar veramente necessario qui? ③ potresti scrivere (n,m)=>B(n,m,'a')invece di(n,m)=>{return B(n,m,'a')}
kennytm il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.