"Bit-Borrow" zwei Nummern

20

Wussten Sie, dass eine kleine Anzahl Bits von einer größeren Anzahl ausleihen kann ? Hier ist ein Beispiel. Sagen wir unsere beiden Zahlen 5 und 14. Schreiben Sie sie zunächst binär auf:

5       14
000101  001110

Zunächst nehmen wir die kleinste auf etwas weg von der größeren Zahl, und wir geben es auf den kleinsten aus Bit auf der anderen Nummer. So

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

Jetzt haben wir

000111  001100

und unsere Zahlen sind 7 und 12. Die erste Zahl ist immer noch kleiner, also fahren wir fort.

000111  001100
001111  001000

Jetzt haben wir 15 und 8, damit wir aufhören können. Wir werden diese Menge von Operationen "Bit-Borrowing" zwei Zahlen nennen. Lassen Sie uns ein anderes Beispiel machen. 20 und 61.

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

Unser Endresultat ist also 32, 63. Lassen Sie uns noch eines tun . 31 und 12. 31 ist bereits größer als 12, es gibt also nichts zu tun! Bit-Ausleihe 31 und 12 ergibt 31 und 12, keine Änderung.

Die Herausforderung

Ihre Herausforderung besteht darin, ein Programm oder eine Funktion zu schreiben, die zwei Zahlen aufnimmt und diese ausleiht. Die beiden Zahlen sind immer positive ganze Zahlen. Ihre Eingabe und Ausgabe kann in jedem vernünftigen Format erfolgen.

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

Es gelten Standardlücken und die kürzeste Antwort in Bytes gewinnt!

DJMcMayhem
quelle

Antworten:

12

Jelly , 11 Bytes

~1¦&N$^µ</¿

Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Hintergrund

Wir können das letzte gesetzte Bit einer ganzen Zahl n wie folgt extrahieren .

n + 1 schaltet alle nachfolgenden gesetzten Bits von n und das benachbarte nicht gesetzte Bit um . Zum Beispiel 10011 2 + 1 = 10100 2 .

Da ~ n = - (n + 1) = -n - 1 , -n = ~ n + 1 ist , wendet -n das obige auf das bitweise NICHT von n an (wodurch alle Bits umgeschaltet werden ), wodurch alle Bits vor dem letzten umgeschaltet werden 1 .

Beispiel: -10100 2 = ~ 10100 2 + 1 = 01011 2 + 1 = 01100 2 .

Indem n & ndash; n das bitweise UND von n und -n genommen wird, werden alle Bits vor dem letzten gesetzten Bit auf Null gesetzt (da in n und -n ungleich ), wodurch das letzte gesetzte Bit von n erhalten wird .

Zum Beispiel 10100 2 & -10.100 2 = 10100 2 & 01100 2 = 00100 2 .

Daher setzt XORing n mit n & ndash ; n das zuletzt gesetzte Bit von n zurück .

Umgekehrt, um das letzte gesetzte Bit von n zu löschen , genügt es, das Obige auf ~ n anzuwenden , woraus wir die Formel n ^ (~ n & - ~ n) ableiten .

Wie es funktioniert

~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].
Dennis
quelle
6

J, 31 26 Bytes

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

Unkomplizierter Ansatz mit Rekursion und bitweisen Tricks. Um das am weitesten rechts stehende Ein ( 1 ) -Bit für einen Wert n auszuschalten (auf 0 zu setzen ) , können Sie bitweise und zwischen n und n -1 vorgehen und das am weitesten rechts liegende Bit einschalten (auf 1 zu setzen ) off ( 0 ) Bit für einen Wert n , können Sie bitweise oder zwischen n und n +1 ausführen .

Verwendung

Die Eingabe besteht aus zwei Ganzzahlen, von denen eine auf die LHS und die andere auf die RHS angewendet wird, und die Ausgabe ist eine Liste der bitgeborgten Werte.

   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

Erläuterung

,`(($:~(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
Meilen
quelle
Gute Antwort! Es tut mir leid, die Herausforderung zu ändern, nachdem Sie eine Antwort gepostet haben, aber ich habe die Herausforderung ein wenig vereinfacht. (Sie müssen die Liste nicht mehr durchlaufen). Dann sollten Sie es etwas kürzer machen.
DJMcMayhem
@DrGreenEggsandIronMan J wendet die Funktion tatsächlich elementweise zwischen den beiden Arrays ohne explizite Rangfolge an. Wenn es keinen anderen Trick gibt, wird er wahrscheinlich gleich bleiben.
Meilen
4

Python, 42 Bytes

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

Danke an @ jimmy23013 für das Golfen mit 4 Bytes! Vielen Dank an @LeakyNun für das Golfen mit 2 Bytes!

Teste es auf Ideone .

Dennis
quelle
3

Mathematica, 46 Bytes

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

Gleiche Methode wie in meiner Lösung in J.

Vielen Dank an @ Martin für das Speichern von 1 Byte und das Erinnern an die Infix-Anwendung ~.

Verwendung

Die Eingabe besteht aus zwei ganzzahligen Argumenten und die Ausgabe ist eine Liste mit den Bit-geliehenen Werten.

Beispiel

Meilen
quelle
Ich dachte, ich würde etwas Lustiges ausprobieren, aber leider ist es ein Byte länger: #//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}&(Vielleicht hast du eine Idee, wie man es verkürzt)
Martin Ender
Das ist eine ordentliche Regel, aber ich kenne mich mit den Golfregeln nicht so gut aus. Ich benutze normalerweise nur Substitution /.und Bedingung /;. Wünschte, Mathematica könnte zwischen boolesch und bitweise wechseln, indem Sie die Argumenttypen auf &&und so untersuchen.
Meilen
3

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

MXG ^ 2x + _ \ 0.BG`HCm.W <FHgVZU2dC 
MXG ^ 2x_ + 0jG2HCm.W <FHgVZU2dC 
Cm.W <FH.bxN ^ 2x_ + 0jN2YZ2dC 
M.W <FH.bxN ^ 2x_ + 0jN2YZ2       <- geänderte Eingabe / Ausgabe Format
 mW <FH.exb ^ 2x_ + 0jb2kZ 
M. W <FH.U ,. | BHB & ZtZZ. 
.W <FH.U ,. | BHB & ZtZZ.          <- geänderte Ein- / Ausgabeformat
 .W <FH.U ,. | bhb. & ZtZ
.W <FH.U,. | Bhb. & T

Testsuite.

Undichte Nonne
quelle
Es tut mir leid, die Herausforderung zu ändern, nachdem Sie eine Antwort gepostet haben, aber ich habe die Herausforderung ein wenig vereinfacht. (Sie müssen die Liste nicht mehr durchlaufen). Zum Glück können Sie es dann aber verkürzen.
DJMcMayhem
@DrGreenEggsandIronMan Es wurde nur ein Byte gespeichert. Pyth ist so effizient.
Undichte Nonne
2

Labyrinth , 37 34 Bytes

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

Probieren Sie es online!

Erläuterung

Schnelle Labyrinth-Grundierung:

  • Labyrinth arbeitet mit zwei Stapeln von Ganzzahlen beliebiger Genauigkeit, main und Hilfszahl , die anfänglich mit einer (impliziten) unendlichen Menge von Nullen gefüllt sind.
  • Der Quellcode ähnelt einem Labyrinth, in dem der Befehlszeiger (IP) Korridoren folgt. Alle interessanten Kontrollabläufe finden an Kreuzungen statt: Wenn die IP mehr als eine Zelle hat, wird die Oberseite des Hauptstapels überprüft. Wenn der Wert negativ ist, dreht sich die IP nach links, wenn es positiv ist, dreht sich die IP nach rechts und ansonsten bewegt sie sich geradeaus. Wenn die gewählte Richtung durch eine Wand (dh ein Leerzeichen) blockiert ist, bewegt sich die IP stattdessen in die entgegengesetzte Richtung.

Das Programm verwendet den gleichen Algorithmus wie die anderen Antworten: Wir ersetzen (a, b)durch (a | a+1, b & b-1)so langea < b . Ich werde eine vollständige Erklärung hinzufügen, nachdem ich versucht habe, noch mehr Golf zu spielen.

Die IP beginnt in der oberen linken Ecke und geht nach rechts. ?liest eine ganze Zahl a. Dann "ist es ein No-Op, aber es ist notwendig zu verhindern, dass sich die IP sofort nach unten bewegt. Dies ist auch eine Sackgasse, so dass sich die IP umdreht und ?erneut ausgeführt wird, um zu lesen b. }dann wechselt man bvon main nach aux , also haben wir jetzt:

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

Das macht |dann nichts, weil es das bitweise ODER von aund nimmt 0. Da wir wissen, dass aes immer positiv ist, dreht sich die IP nach Osten (weil sie nicht nach Westen drehen kann). Dies beginnt die Hauptschleife des Programms. Wir beginnen mit einem kurzen linearen Abschnitt, um zu vergleichen aund 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.

Die IP ist jetzt an einer anderen Kreuzung. Betrachten wir zunächst den Fall, in dem das Ergebnis positiv ist. Das bedeutet b > aund wir müssen noch eine Iteration durchführen. Diese Iteration ist auch vollständig linear. Beachten Sie, dass die Stapel derzeit:

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.

Und dann sind wir wieder am Anfang der Schleife (da aes wieder positiv ist, dreht sich die IP wieder nach Osten).

Wenn irgendwann b-anicht mehr positiv ist, nimmt die IP einen der beiden anderen Pfade. Beachten Sie, dass in beiden Fällen holen wir amit {, dann eine Ecke treffen , wo die IP die Kurve folgt und dann drucken amit !. Jetzt befindet sich der Stack wieder oben, b-awas bedeutet, dass sich die IP in beiden Fällen nach Osten bewegt. Jetzt bleibt nur noch ein kurzes lineares Bit:

;   Discard b-a.
\   Print a linefeed.
!   Print b.
@   Terminate the program.
Martin Ender
quelle
1

Java 7, 73 Bytes

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

Ungolfed & Testfälle:

Probieren Sie es hier aus.

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

Ausgabe:

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

Alte Herausforderungsregeln [ 126 125 123 Bytes]:

ANMERKUNG: Die alten Abfrageregeln verwendeten zwei Ganzzahl-Arrays als Eingabe anstelle von zwei losen Ganzzahlen.

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);}}
Kevin Cruijssen
quelle
Es tut mir leid, die Herausforderung zu ändern, nachdem Sie eine Antwort gepostet haben, aber ich habe die Herausforderung ein wenig vereinfacht. (Sie müssen die Liste nicht mehr durchlaufen). Zum Glück können Sie es dann aber verkürzen.
DJMcMayhem
@ DrGreenEggsandIronMan Bearbeitet. Btw, es ist normalerweise eine schlechte Praxis, die Regeln zu ändern, nachdem die Leute ihre Antworten gepostet haben. Aber wie Sie sagten, sollte es die Byteanzahl senken, damit bin ich in Ordnung. (PS: Sie haben oben nicht alle Antworten kommentiert.)
Kevin Cruijssen
1
Sie können Ihre whileSchleife wie for(;x<y;x|=x+1,y&=y-1);
folgt
Ich weiß es ist. -_-Ich wünschte, ich hätte es von Anfang an besser geschrieben. Zum Glück ist es keine unvernünftige oder drastische Veränderung. Auch ja, ich habe nicht jede Antwort kommentiert, aber ich habe jeden Benutzer informiert. Ich hatte keine Lust, denselben Benutzer mehrmals zu informieren. Ich habe Dennis 'Post nicht kommentiert, aber das liegt daran, dass er einer der Benutzer war, die mich dazu ermutigten, ihn anfangs zu ändern.
DJMcMayhem
1

JavaScript (ES6), 33 Byte

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

Einfacher Port der Antworten von @miles.

Neil
quelle
Du hast den f=Ath am Anfang vergessen : P
Mama Fun Roll
1
Du hast das "schon wieder" vergessen ;-)
Neil
1

Julia, 27 Bytes

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

Probieren Sie es online!

Wie es funktioniert

Wir definieren den binären Operator <|für unsere Zwecke. Es ist in neueren Versionen von Julia undefiniert, wird jedoch vom Parser weiterhin als Operator erkannt. Während \(nicht explizit für Ganzzahlen definiert) ein Byte kürzer ist, müsste es x|-~x<|y&~-ybei seiner hohen Priorität durch ersetzt werden(x|-~x)\(y&~-y) , wodurch die Byte-Anzahl erhöht wird.

<|prüft, ob das erste Argument genau kleiner als das zweite ist. Wenn ja, ruft es sich rekursiv mit den Argumenten x | auf - ~ x = x | (x + 1) und y & ndash; y = y & ndash; (y - 1) .

Durch das Hinzufügen von 1 zu x werden alle nachfolgenden gesetzten Bits und das niedrigste nicht gesetzte Bit umgeschaltet, x | (x + 1) schaltet das niedrigste nicht gesetzte Bit (und keine anderen Bits) um. Ebenso, da durch Subtrahieren von 1 von y alle nachfolgenden nicht gesetzten Bits und das niedrigste gesetzte Bit umgeschaltet werden, ist y & (y + 1) das niedrigste gesetzte Bit um.

Schließlich, wenn die Ungleichung x <y nicht mehr gilt,<| das Paar [x, y] zurückgegeben .

Dennis
quelle
0

MATLAB, 67 66 Bytes

Schleife:

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

rekursiv (67 Bytes):

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

Gleicher Ansatz zum Ändern von Bits wie bei vielen anderen Antworten.

pajonk
quelle
0

Clojure, 63 Bytes

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

Gleiche Methode wie in meiner Lösung in J.

Verwendung

=> (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])
Meilen
quelle