Циклический сдвиг влево на указанное количество бит: проблема с граничными значениями
Мне необходимо реализовать циклический побитовый сдвиг влево, с маленькими числами все отлично работает, но когда ввожу максимальное число для 64бит (9223372036854775807) то мне выдается другое число. Проблема именно в том, что когда я ввожу это максимальное число и сдвигаю на 64 бит (по кругу то есть), код новое число переводит из двоичной в десятичной неправильно
#include <iostream>
#include <sstream>
using namespace std;
//Преобразуем число в массив символов, которые представляют число в двоичном виде
void NumToChars(long long num, char num2[], int arr_size) {
long long one = 1;
for (int i = arr_size - 1; i >= 0; i--) {
if (num & (one << i)) {//сдвигаем биты
num2[arr_size - 1 - i] = '1';
}
else {
num2[arr_size - 1 - i] = '0';
}
}
}
//создаем строку из двоичного представления числа, добавляя пробелы для удобства
string CharsToString(char num2[], int arr_size) {
string s = "";
for (int i = 0; i < arr_size; i++) {
s += num2[i];
if ((i + 1) % 8 == 0)s += " ";
}return s;
}
//Меням биты в двоичном представлении числа
long long ShiftBits(unsigned long long num, int shift) {
unsigned long long res = (num << shift) | (num >> (64 - shift));
return res;
}
//преобразуем двоичное представление в десятиричное число
long long CharsToLongLong(char arr[], int arr_size) {
long long res = 0;
int deg;
for (int i = arr_size - 1; i >= 0; i--) {
if (arr[i] == '1') {
deg = arr_size - 1 - i;
res += pow(2, deg);
}
}return res;
}
int main(int argc, char* argv[]) {
setlocale(LC_ALL, "ru");
//Если количество аргументов указано верно
if (argc == 3) {
unsigned long long num;
int shift;
bool correct[2] = { true,true };
//Создаем из массива символов потоки строк
stringstream convert[2];
for (int i = 0; i < 2; i++) {
convert[i].str(argv[i + 1]);
}
//Конвертируем значения
//конвертируем исходное число
if (!(convert[0] >> num)) // выполняем конвертацию
correct[0] = false; // если конвертация терпит неудачу, то отмечаем это
//конвертируем число для сдвига
if (!(convert[1] >> shift)) // выполняем конвертацию
correct[1] = false; // если конвертация терпит неудачу, то отмечаем это
//Если конвертация прошла успешно
if (correct[0] && correct[1]) {
//Если позиция указана верно
if (shift > 0) {
//Перевод в двоичный вид
char input[64];
NumToChars(num, input, 64);
cout << "Исходное число в десятиричном виде: " << endl << num << endl;
cout << "Исходное число в двоичном виде: " << endl << CharsToString(input, 64) << endl;
//сдвиг
cout << "Сдвиг влево на число бит: " << shift << endl;
char res[64];
unsigned long long r = ShiftBits(num, shift);
NumToChars(r, res, 64);
cout << "Результат сдвига:" << endl << CharsToString(res, 64) << endl;
//перевод из двоичного в лонг лонг
unsigned long long new_num = CharsToLongLong(res, 64);
cout << "Получившееся число: " << endl << new_num << endl;
}
else { cout << "Число сдвига должно быть больше 0" << endl; }
}
//Если конвертация прошла неуспешно
else {
cout << "Не получилось преобразовать следующие числа:" << endl;
if (!correct[0]) { cout << "Исходное число - " << argv[1] << endl; }
if (!correct[1]) { cout << "Число сдвига - " << argv[2] << endl; }
}
}
//если количество аргументов было другое - говорим какие аргументы и в каком порядке должны быть
else {
cout << "Аргументы программы:" << endl;
cout << "1) Исходное число" << endl;
cout << "2) число, на которое нужно сдвинуть влево" << endl;
}
}
Прилагаю пример выполнения
Ответы (1 шт):
Автор решения: AdolfDFO
→ Ссылка
Нашёл проблему. Проблема была в функции CharsToLongLong, из-за
res += pow(2, deg);
Функция pow работает с типом double. Чтобы получить степень двойки, необходимо было использовать побитовый сдвиг и заменить тип данных у deg из int на unsigned long long. Вместо сложения использовать дизъюнкцию
deg = (1ULL <<arr_size- 1-i);
res = res | deg;
