Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Did you know that a small number can borrow bits from a larger number? Here's an example. Let's say our two numbers 5 and 14. First, write them out in binary:

5       14
000101  001110

First we take the smallest on bit away from the larger number, and we give it to the smallest off bit on the other number. So

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

Now we have

000111  001100

and our numbers are 7 and 12. The first number is still smaller, so we continue.

000111  001100
001111  001000

Now we have 15 and 8, so we can stop. We'll call this set of operations "bit-borrowing" two numbers. Let's do another example. 20 and 61.

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

So our end result is 32, 63. Let's do one more. 31, and 12. 31 is already bigger than 12, so there's nothing to do! Bit-borrowing 31 and 12 gives 31 and 12, no change.

The challenge

Your challenge is to write a program or function that takes two numbers and bit-borrows them. The two numbers will always positive integers. Your input and output can be in any reasonable format.

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

Standard loopholes apply, and shortest answer in bytes wins!

share|improve this question

Jelly, 11 bytes

~1¦&N$^µ</¿

Try it online! or verify all test cases.

Background

We can extract the last set bit of an integer n as follows.

n + 1 toggles all trailing set bits of n and the adjacent unset bit. For example, 100112 + 1 = 101002.

Since ~n = -(n + 1) = -n - 1, -n = ~n + 1, so -n applies the above to the bitwise NOT of n (which toggles all bits), thus toggling all bits before the last 1.

For example, -101002 = ~101002 + 1 = 010112 + 1 = 011002.

By taking n & -n the logical AND of n and -n all bits before the last set bit are nullified (since unequal in n and -n), thus yielding the last set bit of n.

For example, 101002 & -101002 = 101002 & 011002 = 001002.

Thus XORing n with n & -n unsets the last set bit of n.

Conversely, to unset the last set bit of n, it suffices to apply the above to ~n, from where we derive the formula n ^ (~n & -~n).

How it works

~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].
share|improve this answer

J, 31 bytes

,`(($:~(23 b.>:))~(17 b.<:))@.<

Straight-forward approach using recursion and bitwise tricks. In order to turn off (set to 0) the right-most on (1) bit for a value n, you can perform bitwise-and between n and n-1, and to turn on (set to 1) the right-most off (0) bit for a value n, you can perform bitwise-or between n and n+1.

Usage

The input consists of two integers, one applied on the LHS and the other on the RHS, and the output is a list of the bit-borrowed values.

   f =: ,`(($:~(23 b.>:))~(17 b.<:))@.<
   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

Explanation

,`(($:~(23 b.>:))~(17 b.<:))@.<  Input: x on LHS, y on RHS
u`(            v           )@.<  If x < y, execute v, else u
,                                Form a 2-element array [x, y] and return
                        <:       Decrement y
                   17 b.         Perform bitwise-and on y and y-1, call it y'
             >:                  Increment x
        23 b.                    Perform bitwise-or on x and x+1, call it x'
    $:                           Call recursively on x' and y'
share|improve this answer
    
Nice answer! Sorry to change the challenge after you've posted an answer, but I've simplified the challenge a little bit. (you don't need to iterate over the list any more). That should let you shorten it a little bit more. – Dr Green Eggs and Iron Man 1 hour ago
    
@DrGreenEggsandIronMan J is actually applying the function element-wise between the two arrays without any explicit ranking, which is nice. Unless there's another trick, it will probably stay the same. – miles 1 hour ago

Pyth, 29 27 25 22 21 20 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      <-- changed input/output format
m.W<FH.exb^2x_+0jb2kZ
m.W<FH.U,.|bhb.&ZtZZ

Test suite.

share|improve this answer
    
Sorry to change the challenge after you've posted an answer, but I've simplified the challenge a little bit. (you don't need to iterate over the list any more). Although thankfully that will allow you to shorten it. – Dr Green Eggs and Iron Man 1 hour ago

Python, 42 bytes

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

Thanks to @jimmy23013 for golfing off 4 bytes! Thanks to @LeakyNun for golfing off 2 bytes!

Test it on Ideone.

share|improve this answer

Mathematica, 46 bytes

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

Same method as used in my solution in J.

Thanks to @Martin for saving 1 byte and reminding me of infix application ~.

Usage

The input consists of two integer arguments and the output is a list with the bit-borrowed values.

Example

share|improve this answer
    
Thought I'd try something funny, but unfortunately it's a byte longer: #//.{x_,y_}/;x<y:>{BitOr[x,x+1],BitAnd[y,y-1]}& (maybe you have an idea how to shorten it though) – Martin Ender 58 mins ago
    
That's a neat rule, but I'm not very familiar with golfing rules. I typically only use substitution /. and condition /;. Wish Mathematica could switch between boolean and bitwise by inspecting argument types to && and such. – miles 51 mins ago

Julia, 27 bytes

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

Try it online!

share|improve this answer

05AB1E, 16 15 bytes

[D`›#`D<&sD>~s‚

Try it online

share|improve this answer

JavaScript (ES6), 31 bytes

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

Simple port of the answers by @miles.

share|improve this answer

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 & test cases:

Try it here.

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

Output:

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

Old challenge rules [126 125 123 bytes]:

NOTE: The old challenge rules used two integer-arrays as input, instead of two loose integers.

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);}}
share|improve this answer
    
Sorry to change the challenge after you've posted an answer, but I've simplified the challenge a little bit. (you don't need to iterate over the list any more). Although thankfully that will allow you to shorten it. – Dr Green Eggs and Iron Man 1 hour ago
    
@DrGreenEggsandIronMan Edited. Btw, it's usually bad practice to change the rules after people have posted their answers.. But as you said, it should lower the byte-count, so I'm ok with it. (PS: You haven't made the comment above on everyone's answer.) – Kevin Cruijssen 1 hour ago
1  
You can rewrite your while loop like this for(;x<y;x|=x+1,y&=y-1); – cliffroot 55 mins ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.