"Bit-loan" due numeri


20

Sapevi che un numero piccolo può prendere in prestito bit da un numero più grande? Ecco un esempio Diciamo che i nostri due numeri 5 e 14. Innanzitutto, scrivili in binario:

5       14
000101  001110

In primo luogo prendiamo il più piccolo sul po 'lontano dal numero maggiore, e diamo al più piccolo fuori po' l'altro numero. Così

This bit turns off
            |
            v
000101  001110
    ^
    |
This bit turns on

Ora abbiamo

000111  001100

e i nostri numeri sono 7 e 12. Il primo numero è ancora più piccolo, quindi continuiamo.

000111  001100
001111  001000

Ora abbiamo 15 e 8, quindi possiamo fermarci. Chiameremo questo insieme di operazioni "prendere in prestito bit" due numeri. Facciamo un altro esempio. 20 e 61.

20        61
010100    111101
010101    111100
010111    111000
111111    100000
63        32

Quindi il nostro risultato finale è 32, 63. Facciamo ancora uno . 31 e 12. 31 è già più grande di 12, quindi non c'è niente da fare! Il prestito di bit 31 e 12 dà 31 e 12, nessuna modifica.

La sfida

La tua sfida è scrivere un programma o una funzione che prende due numeri e li prende in prestito a bit. I due numeri saranno sempre numeri interi positivi. I tuoi input e output possono essere in qualsiasi formato ragionevole.

Test IO:

Input: 2, 3
Output: 3, 2

Input: 3, 2
Output: 3, 2

Input: 8, 23
Output: 31, 0

Input: 42, 81
Output: 63, 0

Input: 38, 41
Output: 47, 32

Input: 16, 73
Output: 23, 0

Input: 17, 17
Output: 17, 17

Si applicano scappatoie standard e vince la risposta più breve in byte!

Risposte:


12

Gelatina , 11 byte

~1¦&N$^µ</¿

Provalo online! o verifica tutti i casi di test .

sfondo

Possiamo estrarre l'ultimo bit impostato di un numero intero n come segue.

n + 1 attiva / disattiva tutti i bit impostati finali di n e il bit disinserito adiacente. Ad esempio, 10011 2 + 1 = 10100 2 .

Poiché ~ n = - (n + 1) = -n - 1 , -n = ~ n + 1 , quindi -n applica quanto sopra al NOT bit a bit di n (che attiva / disattiva tutti i bit), quindi attivando tutti i bit prima dell'ultimo 1 .

Ad esempio, -10100 2 = ~ 10100 2 + 1 = 01011 2 + 1 = 01100 2 .

Prendendo n & -n il bit bit AND di n e -n tutti i bit prima dell'ultimo bit impostato vengono annullati (poiché disuguali in n e -n ), producendo così l'ultimo bit impostato di n .

Ad esempio, 10100 2 e -10100 2 = 10100 2 e 01100 2 = 00100 2 .

Pertanto XORing n con n & -n disattiva l'ultimo bit impostato di n .

Al contrario, per annullare l'ultimo bit impostato di n , è sufficiente applicare quanto sopra a ~ n , da cui deriviamo la formula n ^ (~ n & - ~ n) .

Come funziona

~1¦&N$^µ</¿  Main link. Argument: A (list of pairs)

          ¿  While loop:
        </     Condition: Reduce p by less-than. True iff x < y.
       µ       Body chain:
~1¦              Apply bitwise NOT to the x, first item of the pair.
     $           Convert the two links to the left into a monadic chain.
    N              Negate; multiply [~x, y] by -1, yielding [-~x, -y].
   &               Logical AND. Yields [-~x & ~x, -y & y].
      ^            Vectorized XOR with p. Yields [(-~x & ~x) ^ x, (-y & y) ^ y].

6

J, 31 26 byte

,`(($:~(OR>:))~(AND<:))@.<

Approccio diretto con ricorsione e trucchi bit per bit. Per disattivare (impostare su 0 ) il bit on ( 1 ) più a destra per un valore n , è possibile eseguire bit a bit tra n e n -1 e attivare (impostare su 1 ) il più a destra off ( 0 ) bit per un valore n , è possibile eseguire bit a bit o tra n e n +1.

uso

L'input è composto da due numeri interi, uno applicato su LHS e l'altro su RHS, e l'output è un elenco dei valori presi in prestito in bit.

   f =: ,`(($:~(OR>:))~(AND<:))@.<
   2 f 3
3 2
   3 f 2
3 2
   8 f 23
31 0
   42 f 81
63 0
   38 f 41
47 32
   16 f 73
23 0
   17 f 17
17 17

Spiegazione

,`(($:~(OR>:))~(AND<:))@.<  Input: x on LHS, y on RHS
                            If x < y,
,                             Form a 2-element array [x, y] and return
                            Else
                   <:         Decrement y
                AND           Perform bitwise-and on y and y-1, call it y'
          >:                  Increment x
        OR                    Perform bitwise-or on x and x+1, call it x'
    $:                        Call recursively on x' and y' and return

Bella risposta! Mi dispiace cambiare la sfida dopo aver pubblicato una risposta, ma ho semplificato un po 'la sfida. (non è necessario scorrere più nell'elenco). Ciò dovrebbe consentirti di accorciarlo un po 'di più.
DJMcMayhem

@DrGreenEggsandIronMan J sta effettivamente applicando la funzione elemento-saggio tra i due array senza alcun posizionamento esplicito, il che è carino. A meno che non ci sia un altro trucco, probabilmente rimarrà lo stesso.
miglia,

4

Python, 42 byte

f=lambda x,y:x<y and f(x|x+1,y&y-1)or(x,y)

Grazie a @ jimmy23013 per giocare a golf con 4 byte! Grazie a @LeakyNun per il golf off 2 byte!

Provalo su Ideone .


3

Mathematica, 46 byte

If[#<#2,BitOr[#,#+1]~#0~BitAnd[#2,#2-1],{##}]&

Stesso metodo usato nella mia soluzione in J.

Grazie a @ Martin per aver salvato 1 byte e ricordandomi dell'applicazione infix ~.

uso

L'input è costituito da due argomenti interi e l'output è un elenco con i valori presi in prestito in bit.

Esempio


Pensavo di provare qualcosa di divertente, ma sfortunatamente è un byte più lungo: #//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}&(forse hai un'idea di come accorciarlo)
Martin Ender,

Questa è una regola ordinata, ma non ho molta familiarità con le regole del golf. Di solito uso solo sostituzione /.e condizioni /;. Vorrei che Mathematica potesse alternare tra booleano e bit a bit esaminando i tipi di argomenti &&e simili.
miglia,

3

Pyth, 29 27 25 22 21 20 19 18 16 byte

MXG ^ _ 2x + \ 0.BG`HCm.W <FHgVZU2dC 
MXG ^ 2x_ + 0jG2HCm.W <FHgVZU2dC 
Cm.W <FH.bxN ^ 2x_ + 0jN2YZ2dC 
m.W <FH.bxN ^ 2x_ + 0jN2YZ2       <- mutato input / output formato
 mW <FH.exb ^ 2x_ + 0jb2kZ 
m.W <FH.U ,. | bhb. & ZtZZ 
.W <FH.U ,. | bhb. & ZtZZ          <- formato di input / output modificato
 .W <FH.U ,. | bhb. & ZTZ
.W <FH.U ,. |. Bhb & t

Suite di test.


Mi dispiace cambiare la sfida dopo aver pubblicato una risposta, ma ho semplificato un po 'la sfida. (non è necessario scorrere più nell'elenco). Anche se per fortuna questo ti permetterà di accorciarlo.
DJMcMayhem

@DrGreenEggsandIronMan Ha salvato solo un byte. Pyth è così efficiente.
Leaky Nun,


2

Labyrinth , 37 34 byte

?"
}
|=:{:
)   }
: :;-{
=&( {!;\!@

Provalo online!

Spiegazione

Primer Quick Labyrinth:

  • Labyrinth opera su due pile di numeri interi di precisione arbitraria, principale e ausiliaria , che inizialmente vengono riempiti con una quantità (implicita) infinita di zeri.
  • Il codice sorgente assomiglia a un labirinto, in cui il puntatore dell'istruzione (IP) segue i corridoi. Tutto il flusso di controllo interessante avviene nelle giunzioni: quando l'IP ha più di una cella in cui andare, viene ispezionata la parte superiore dello stack principale. Se il valore è negativo, l'IP gira a sinistra, se è positivo, l'IP gira a destra, altrimenti si sposta in avanti. Se la direzione scelta è bloccata da un muro (cioè uno spazio), l'IP si sposta invece nella direzione opposta.

Il programma utilizza lo stesso algoritmo come le altre risposte: sostituiamo (a, b)con (a | a+1, b & b-1)più a lungo a < b. Aggiungerò una spiegazione completa dopo aver provato ancora a giocare a golf.

L'IP inizia nell'angolo in alto a sinistra, andando a destra. ?legge un numero intero a. Quindi "è una no-op, ma è necessario per impedire all'IP di spostarsi immediatamente verso il basso. Anche questo è un vicolo cieco, quindi l'IP si gira e si esegue di ?nuovo per leggere b. }quindi passa bda principale ad aux , quindi ora abbiamo:

Main [ ... 0 a | b 0 ...] Aux

L' |allora non fa nulla, perché ci vuole l'OR bit a bit di ae 0. Poiché sappiamo che aè sempre positivo, l'IP gira a est (perché non può girare a ovest). Questo inizia il ciclo principale del programma. Iniziamo con una breve sezione lineare per confrontare ae b:

=   Swap tops of stacks, i.e. swap a and b.
:   Duplicate b.
{   Pull a over to main.
:   Duplicate a.
}   Push one copy back to aux.
-   Compute b-a.

L'IP è ora in un altro incrocio. Innanzitutto, consideriamo il caso in cui il risultato è positivo. Ciò significa b > ache dobbiamo eseguire un'altra iterazione. Anche questa iterazione è completamente lineare. Si noti che le pile sono attualmente:

Main [ ... 0 b (b-a) | a 0 ...] Aux

;   Discard b-a.
:   Duplicate b.
(   Decrement.
&   Bitwise AND with b, clearing the least-significant 1.
=   Swap new b with old a.
:   Duplicate a.
)   Increment.
|   Bitwise OR with a, setting the least-significant 0.

E poi torniamo all'inizio del loop (dato che aè di nuovo positivo, l'IP gira di nuovo ad est).

Se ad un certo punto b-anon è più positivo, l'IP prenderà uno degli altri due percorsi. Si noti che in entrambi i casi prendiamo acon {, quindi colpiamo un angolo in cui l'IP segue la curva e quindi stampiamo acon !. Ora la parte superiore dello stack è di nuovo, il b-ache significa che in entrambi i casi l'IP finirà per spostarsi verso est. Tutto ciò che rimane è un breve bit lineare ora:

;   Discard b-a.
\   Print a linefeed.
!   Print b.
@   Terminate the program.

1

Java 7, 73 byte

void d(int x,int y){while(x<y){x|=x+1;y&=y-1;}System.out.print(x+","+y);}

Casi non testati e test:

Provalo qui.

public class Main{
  static void d(int x, int y){
    while(x < y){
      x |= x + 1;
      y &= y - 1;
    }
    System.out.print(x + "," + y);
  }

  public static void main(String[] a){
    print(2, 3);
    print(3, 2);
    print(8, 23);
    print(42, 81);
    print(38, 41);
    print(16, 73);
    print(17, 17);
  }

  public static void print(int a, int b){
    d(a, b);
    System.out.println();
  }
}

Produzione:

3,2
3,2
31,0
63,0
47,32
23,0
17,17

Vecchie regole di sfida [ 126 125 123 byte]:

NOTA: le vecchie regole di sfida utilizzavano due array di numeri interi come input, anziché due numeri interi sciolti.

void d(int[]a,int[]b){int i=-1,x,y;while(++i<a.length){x=a[i];y=b[i];for(;x<y;x|=x+1,y&=y-1);System.out.println(x+","+y);}}

Mi dispiace cambiare la sfida dopo aver pubblicato una risposta, ma ho semplificato un po 'la sfida. (non è necessario scorrere più nell'elenco). Anche se per fortuna questo ti permetterà di accorciarlo.
DJMcMayhem

@DrGreenEggsandIronMan Edited. A proposito, di solito è una cattiva pratica cambiare le regole dopo che le persone hanno pubblicato le loro risposte .. Ma come hai detto, dovrebbe abbassare il conteggio dei byte, quindi sto bene. (PS: non hai fatto il commento sopra sulla risposta di tutti.)
Kevin Cruijssen,

1
Puoi riscrivere il tuo whileloop in questo modofor(;x<y;x|=x+1,y&=y-1);
cliffroot,

Lo so che è. -_-Vorrei averlo scritto meglio dall'inizio. Per fortuna non è un cambiamento irragionevole o drastico. Inoltre, sì, non ho commentato tutte le risposte, ma ho informato tutti gli utenti. Non mi andava di informare lo stesso utente più volte. Non ho commentato il post di Dennis, ma è perché era uno degli utenti che mi ha incoraggiato a cambiarlo inizialmente.
DJMcMayhem

1

JavaScript (ES6), 33 byte

f=(n,m)=>n<m?f(n|n+1,m&m-1):[n,m]

Porta semplice delle risposte di @miles.


f=All'inizio hai dimenticato l' at: P
Mama Fun Roll,

1
Hai dimenticato il "di nuovo" ;-)
Neil il

1

Julia, 27 byte

x<|y=x<y?x|-~x<|y&~-y:[x,y]

Provalo online!

Come funziona

Definiamo l'operatore binario <|per i nostri scopi. Non è definito nelle ultime versioni di Julia, ma è ancora riconosciuto come operatore dal parser. Mentre \(non definito esplicitamente per numeri interi) è più corto di un byte, la sua precedenza elevata richiederebbe la sostituzione x|-~x<|y&~-ycon(x|-~x)\(y&~-y) , aumentando così il conteggio dei byte.

<|controlla se il suo primo argomento è strettamente inferiore al secondo. In tal caso, si chiama ricorsivamente con argomenti x | - ~ x = x | (x + 1) e y & ~ -y = y & (y - 1) .

Poiché l'aggiunta di 1 a x attiva / disattiva tutti i bit impostati finali e il bit unset più basso, x | (x + 1) attiva / disattiva il bit unset più basso (e nessun altro bit). Allo stesso modo, poiché sottraendo 1 da y attiva / disattiva tutti i bit non impostati finali e il bit impostato più basso, y & (y + 1) attiva / disattiva il bit impostato più basso.

Infine, quando la disuguaglianza x <y non è più valida, <|restituisce la coppia [x, y] .


0

MATLAB, 67 66 byte

ciclo continuo:

function[]=f(x,y)
while x<y
x=bitor(x,x+1);y=bitand(y,y-1);end
x,y

ricorsivo (67 byte):

function[]=f(x,y)
if x<y
f(bitor(x,x+1),bitand(y,y-1))
else
x,y
end

Stesso approccio al cambio di bit come molte altre risposte.


0

Clojure, 63 byte

#(if(< % %2)(recur(bit-or %(inc %))(bit-and %2(dec %2)))[% %2])

Stesso metodo usato nel mio soluzione in J.

uso

=> (def f #(if(< % %2)(recur(bit-or %(inc %))(bit-and %2(dec %2)))[% %2]))
=> (f 38 41)
[47 32]
=> (map (partial apply f) [[2 3] [3 2] [8 23] [42 81] [38 41] [16 73] [17 17]])
([3 2] [3 2] [31 0] [63 0] [47 32] [23 0] [17 17])
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.