#include <iostream>
#include <string>
#include <stdexcept>
#include <algorithm>
// Handles edge cases
// Validates i and j
// Prevents undefined behavior from shifting by ≥ 64 bits
// Masks M so only the required bits are copied
// Convert unsigned long long to binary string without leading zeros
std::string to_binary(unsigned long long x) {
if (x == 0) return "0";
std::string s;
while (x > 0) {
s.push_back((x & 1) ? '1' : '0');
x >>= 1;
}
std::reverse(s.begin(), s.end());
return s;
}
// Copy bits from M into N between bit positions [i, j]
unsigned long long copy_bits(unsigned long long N,
unsigned long long M,
int i, int j)
{
if (i < 0 || j < 0 || i > j || j >= 63) {
throw std::invalid_argument("Invalid bit range");
}
int length = j - i + 1;
// Mask for bits i..j
unsigned long long mask = ((1ULL << length) - 1) << i;
// Clear bits i..j in N
unsigned long long N_cleared = N & ~mask;
// Take only the needed bits from M and shift into place
unsigned long long M_shifted = (M & ((1ULL << length) - 1)) << i;
return N_cleared | M_shifted;
}
int main() {
// N: 100 011111 00
// M: 110011
// Result: 100 110011 00
unsigned long long N = 0b10001111100ULL;
unsigned long long M = 0b110011ULL;
int i = 2;
int j = 7;
unsigned long long result = copy_bits(N, M, i, j);
std::cout << "N: " << to_binary(N) << "\n";
std::cout << "M: " << to_binary(M) << "\n";
std::cout << "Result: " << to_binary(result) << "\n";
}
/*
OUTPUT:
N: 10001111100
M: 110011
Result: 10011001100
*/