Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.thealgorithms.bitmanipulation;

/**
* Implementation to count number of bits to be flipped to convert A to B
*
* Problem: Given two numbers A and B, count the number of bits needed to be
* flipped to convert A to B.
*
* Example:
* A = 10 (01010 in binary)
* B = 20 (10100 in binary)
* XOR = 30 (11110 in binary) - positions where bits differ
* Answer: 4 bits need to be flipped
*
* Time Complexity: O(log n) - where n is the number of set bits
* Space Complexity: O(1)
*
*@author [Yash Rajput](https://github.com/the-yash-rajput)
*/
public final class CountBitsFlip {

private CountBitsFlip() {
throw new AssertionError("No instances.");
}

/**
* Counts the number of bits that need to be flipped to convert a to b
*
* Algorithm:
* 1. XOR a and b to get positions where bits differ
* 2. Count the number of set bits in the XOR result
* 3. Use Brian Kernighan's algorithm: n & (n-1) removes rightmost set bit
*
* @param a the source number
* @param b the target number
* @return the number of bits to flip to convert A to B
*/
public static long countBitsFlip(long a, long b) {
int count = 0;

// XOR gives us positions where bits differ
long xorResult = a ^ b;

// Count set bits using Brian Kernighan's algorithm
while (xorResult != 0) {
xorResult = xorResult & (xorResult - 1); // Remove rightmost set bit
count++;
}

return count;
}

/**
* Alternative implementation using Long.bitCount().
*
* @param a the source number
* @param b the target number
* @return the number of bits to flip to convert a to b
*/
public static long countBitsFlipAlternative(long a, long b) {
return Long.bitCount(a ^ b);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.thealgorithms.bitmanipulation;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Random;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
* Unit tests for CountBitsFlip.
* Covers:
* - simple examples
* - zeros and identical values
* - negative numbers and two's complement edge cases
* - Long.MIN_VALUE / Long.MAX_VALUE
* - randomized consistency checks between two implementations
*/
@DisplayName("CountBitsFlip Tests")
class CountBitsFlipTest {

@Test
@DisplayName("Example: A=10, B=20 => 4 bits")
void exampleTenTwenty() {
long a = 10L;
long b = 20L;
long expected = 4L;
assertEquals(expected, CountBitsFlip.countBitsFlip(a, b), "Brian Kernighan implementation should return 4");
assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b), "Long.bitCount implementation should return 4");
}

@Test
@DisplayName("Identical values => 0 bits")
void identicalValues() {
long a = 123456789L;
long b = 123456789L;
long expected = 0L;
assertEquals(expected, CountBitsFlip.countBitsFlip(a, b));
assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b));
}

@Test
@DisplayName("Both zeros => 0 bits")
void bothZeros() {
assertEquals(0L, CountBitsFlip.countBitsFlip(0L, 0L));
assertEquals(0L, CountBitsFlip.countBitsFlipAlternative(0L, 0L));
}

@Test
@DisplayName("Small example: A=15 (1111), B=8 (1000) => 3 bits")
void smallExample() {
long a = 15L; // 1111
long b = 8L; // 1000
long expected = 3L; // differs in three low bits
assertEquals(expected, CountBitsFlip.countBitsFlip(a, b));
assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b));
}

@Test
@DisplayName("Negative values: -1 vs 0 => 64 bits (two's complement all ones)")
void negativeVsZero() {
long a = -1L;
long b = 0L;
long expected = 64L; // all 64 bits differ
assertEquals(expected, CountBitsFlip.countBitsFlip(a, b));
assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b));
}

@Test
@DisplayName("Long.MIN_VALUE vs Long.MAX_VALUE => 64 bits")
void minMaxLongs() {
long a = Long.MIN_VALUE;
long b = Long.MAX_VALUE;
long expected = 64L; // MAX ^ MIN yields all ones on 64-bit long
assertEquals(expected, CountBitsFlip.countBitsFlip(a, b));
assertEquals(expected, CountBitsFlip.countBitsFlipAlternative(a, b));
}

@Test
@DisplayName("Randomized consistency: both implementations agree across many pairs")
void randomizedConsistency() {
final int iterations = 1000;
final Random rnd = new Random(12345L); // deterministic seed for reproducibility

for (int i = 0; i < iterations; i++) {
long a = rnd.nextLong();
long b = rnd.nextLong();

long res1 = CountBitsFlip.countBitsFlip(a, b);
long res2 = CountBitsFlip.countBitsFlipAlternative(a, b);

assertEquals(res2, res1, () -> String.format("Mismatch for a=%d, b=%d: impl1=%d, impl2=%d", a, b, res1, res2));
}
}
}