Перевод из десятичной системы с двоичную С++

Рейтинг: 0Ответов: 3Опубликовано: 22.05.2023
#include <iostream>
#include <cmath>
using namespace std;

void Translation(int& Number) {
    int a = 2;
    int i = 0;
    while (Number > pow(a, i))
    {
        i++;
    }
    int* arr = new int[i];
    for (int j = 0; j < i; j++) {
        if (Number % 2 == 0) {
            arr[j] = 0;
            Number /= 2;
        }
        if (Number % 2 == 1) {
            arr[j] = 1;
            Number /= 2;
        }
    }

    for (int j = i - 1; j >= 0; j--) {
        cout << arr[j] << " ";
    }
}

int main()
{
    int Number;
    cin >> Number;
    Translation(Number);
}

Не могу понять, почему у меня неправильно переводит из дясятичной в двоичную. Условно, 10, у меня выводится как "0011". Предполагаю, проблема в цикле for в функции Translation.

Ответы

▲ 3Принят

Самая главная ваша ошибка — что вы после проверки на четность проверяете на нечетность изменившееся число. Смотрите сами для 10 — в первом if вы получаете 5, и тут же идете во второй блок if...

Давайте немного подправим...

#include <iostream>
#include <cmath>
using namespace std;

void Translation(int& Number)
{
    int i = 0;
    while (Number >= (1<<i))   // 1<<i — то же, что и 2 в степени i
    {
        i++;
    }
    int* arr = new int[i];
    for (int j = 0; j < i; j++)
    {
        arr[j] = Number%2;
        Number /= 2;
    }

    for (int j = i - 1; j >= 0; j--) {
        cout << arr[j] << " ";
    }
}

int main()
{
    int Number;
    cin >> Number;
    Translation(Number);
}

Но я бы предпочел использовать строки, а не массивы. Например, у вас из-за динамически выделяемого массива, который вы не удаляете — утечка памяти. Далее, у вас функция делает два дела: переводит число в другую систему и выводит его. При нормальном проектировании каждая функция должна заниматься своим единственным делом. Так что вот как вариант:

#include <iostream>
#include <cmath>
#include <string>
using namespace std;

string Translation(int Number)
{
    if (Number == 0) return "0";
    string r;
    while(Number)
    {
        r = char('0' + Number%2) + r;
        Number /= 2;
    }
    return r;
}

int main()
{
    int Number;
    cin >> Number;
    cout << Translation(Number);
}
▲ 0

Для чистых Си можно использовать битовый сдвиг, темболее он работает правильно как с singed так и unsigned интом.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BITS_IN_INT sizeof(int) * 8

void toBitset(int in, char *out) {
    int c, d, t;
    t = 0;
    if (out == NULL) {
        exit(EXIT_FAILURE);
    }
    for (c = BITS_IN_INT-1 ; c >= 0 ; c--) {
        d = in >> c;
        *(out+t) =  (d & 1) ? '1' : '0';
        t++;
    }
    *(out+t) = '\0';
}

int main()
{
    const unsigned size = BITS_IN_INT + 1;
    char buffer[size];
    memset(buffer, 0, size);
    int value;
    scanf("%d+", &value);
    toBitset(value, buffer);
    printf("%s\n", buffer);
    return 0;
}

На плюсах вообще не стоит заморачиваться там есть bitset, который в себе содержит полный пакет для работы с битовыми опирациями.

#include <bitset>
int n = 12345; // the number we’ll print out in binary 
std::cout << std::bitset<32>(n); 

И да... Кончайте эту ересть с делением инта на 2, это не к чему хорошему не приведёт! Как со стороны скорости так и со стороны багов.

▲ 0

Сама идея деления на 2 изначально неверная. Битовый сдвиг - вот что тут нужно. К тому же достаточно написать один шаблон на все целочисленные типы, кроме bool:

#include <string>
#include <iostream>
#include <concepts>
#include <limits>
#include <cstdint>

template<typename T>
concept binreppable = std::integral<T> && !std::same_as<T,bool>;

template<binreppable T>
std::string binrep(T number) {
    std::string rep;
    rep.reserve(sizeof(T)*8 + 1);
    for (int shift = sizeof(T)*8-1; shift >= 0; --shift) 
        rep.push_back(((number >> shift) & 1) ? '1' : '0');
    return rep;
}

int main() {
    std::cout
        << binrep(10)   << std::endl
        << binrep(0b10) << std::endl
        << binrep(010)  << std::endl
        << binrep(0x10) << std::endl
        << binrep(std::numeric_limits<std::int8_t>::max())   << std::endl
        << binrep(std::numeric_limits<std::uint8_t>::max())  << std::endl
        << binrep(std::numeric_limits<std::int16_t>::max())  << std::endl
        << binrep(std::numeric_limits<std::uint16_t>::max()) << std::endl
        << binrep(std::numeric_limits<std::uint32_t>::max()) << std::endl
        << binrep(std::numeric_limits<std::int32_t>::max())  << std::endl
        << binrep(std::numeric_limits<std::uint64_t>::max()) << std::endl
        << binrep(std::numeric_limits<std::int64_t>::max())  << std::endl;
    return 0;
}

Таким образом, длина бинарного представления будет соответсовать битовому размеру самого числа. А концепт в шаблоне не даст передать недопустимый тип (C++20).