Разминка для мозгов: перевод числа из dec в bin

А вот с этим — не согласен

Согласен, погорячился с длинной арифметикой :\

из cstdlib

Вызвать itoa( toBin, binstr, 2 ) :D

#include <iostream>
#include <Windows.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>

int main()
{
    using namespace std;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // A=10, B=11, ... Y=34, Z=35
    char m[100]; // исходное число (действительное)
    short decimal[100]; // символы целой части исходного числа в десятичной с.с.
    short fractional[100]; // символы дробной части исходного числа в десятичной с.с.
    short i, j, k, n, findPoint;
    bool isError, isFound, isDigit;
    /* i - номер символа в строке m; j - счётчик (соответствует значению символа)
    k, n - количество пробелов в целой и дробной части числа соответственно */
    // представление каждого символа исходного числа в десятичной с.с.
    printf ("Введите число в исходной системе счисления и нажмите 'Enter'.\n");
    printf ("Формат ввода: целая_часть.дробная_часть \n");
    printf ("Для завершения работы программы введите '000' : \n");
    do {
        fflush(stdin);
        gets(m);
        isError = false, isFound = false, isDigit = false;
        k = 0, n = 0;
        for (i = 0; i < strlen(m); i++)
        {
            if (m[i] == ' ') {
                if (!isDigit) {
                    for (j = 0; j <= strlen(m); j++)
                    {
                        if (m[j] == ' ') continue;
                        if (m[j] != ' ' && m[j] != '.') {
                            isDigit = true;
                            break;
                        }
                    }
                    if (!isDigit) isError = true;
                    else {
                        if (!isFound) k++;
                        else n++;
                    }
                }
                else { 
                    if (!isFound) k++;
                    else n++;
                    continue;
                }
            }
            if (m[i] == '.') {
                isFound = true;
                findPoint = i;
                for (j = i + 1; j <= strlen(m); j++)
                    if (m[j] == '.') isError = true;
            }
            j = 0;
            if (m[i] != '.' && m[i] != ' ') {
                while (j < strlen(digits) && digits[j] != m[i]) j++;
                if (j == strlen(digits)) isError = true;
                if (!isFound) decimal[i-k] = j;
                else fractional[i-findPoint-1] = j;
            }
            if (isError) break;
        }
        if (!isError) {
            //  перевод исходного числа в десятичную с.с.
            int startBase, err;
            double decimalNumber = 0.0; // целая часть исходного числа в десятичной с.с.
            double fractionalNumber = 0.0; // дробная часть исходного числа в десятичной с.с.
            double number;
            do {
                fflush(stdin);
                printf ("Введите исходную систему счисления: ");
                err = scanf("%d", &startBase);
            } while (err == 0 || startBase < 1 || startBase > 36);
            if (!isFound) {
                for (i = strlen(m) - k - 1; i >= 0; i--)
                    decimalNumber += decimal[i] * (pow(startBase, strlen(m) - k - 1 - i));
            }
            else {
                for (i = findPoint - k - 1; i >= 0; i--)
                    decimalNumber += decimal[i] * (pow(startBase, findPoint - k - 1 - i));
                for (i = 0; i < strlen(m) - findPoint - n - 1; i++)
                    fractionalNumber += fractional[i] * (pow(startBase, -i - 1));
            }
            number = decimalNumber + fractionalNumber;
            // перевод числа с десятичной с.с. в итоговою
            int finalBase;
            do {
                fflush(stdin);
                printf ("Введите итоговую систему счисления: ");
                err = scanf("%d", &finalBase);
            } while (err == 0 || finalBase < 1 || finalBase > 36);
            int num = (int)number;
            short macro[100];
            short lenght = 0;
            do {
                macro[lenght] = num % finalBase;
                lenght++;
                num /= finalBase;
            } while (num >= finalBase);
            macro[lenght] = num;
            for (i = lenght; i >= 0; i--)
                printf ("%c", digits[macro[i]]);
            // Перевод дробной части с точностью 7 знаков
            number = number - (int)number;
            for (lenght = 0; lenght < 7; lenght++)
            {
                number = number * finalBase;
                macro[lenght] = (int)number;
                number = number - (int)number;
            }
            printf(".");
            for (i = 0; i < lenght; i++)
                printf("%c", digits[macro[i]]);
            printf ("\n");
        }
        else if ((strcmp(m, "000") != 0)) 
            printf("Ваше число содержит недопустимые символы. Повторите ввод.\n");
    } while (strcmp (m, "000") != 0);
    return 0;
}

или поразвлекаться с stdtoll из cstdlib

С strtoll всё действительно становится намного проще:

#include <cstdlib> //strtoll
#include <cstdio>  //printf, gets, puts, putc
#include <cerrno>  //errno
#include <climits> //LLONG_MAX LLONG_MIN
#include <cstring> //strlen

typedef unsigned int udword;
typedef long long qword;

const udword MAX_32_BIT = 0xFFFFFFFF;
const udword BITS_NUM = 32;

int main()
{

    char strnum[100];
    std::fgets( strnum, 100, stdin );

    qword num;
    char *endptr;
    num = std::strtoll( strnum, &endptr, 10 );

    if ( ( ( num == LLONG_MAX || num == LLONG_MIN ) && errno == ERANGE ) ||
         num > MAX_32_BIT || num < 0 )
    {
        std::printf( "fuck you\n" );
        return 1;
    }

    char bitstr[BITS_NUM + 1] = { 0, };

    for ( qword t = num, i = 0; t > 0; t /= 2, i++ )
    {
        bitstr[i] = '0' + ( t % 2 );
    }

    std::printf("dec %lld = bin ", num );
    for ( int i = std::strlen( bitstr ) - 1; i >= 0; i-- )
    {
        std::putc( bitstr[i], stdout );
    }
    std::putc( '\n', stdout );

    return 0;
}

porshe, твоя программа для 0 не выводит двоичного представления.

Простая проверка на 0, полагаю, должна решить эту проблему. Можно ещё в цикле условие выполнения на t >= 0 поменять.

Мне кажется, ты немного перемудрил. Последний кусок можно написать проще:

    char bitstr[BITS_NUM + 1] = { 0, };
    int i = BITS_NUM - 1;
    uqword t = num;

    do
    {
        bitstr[i--] = '0' + (t % 2);
        t /= 2;
    } while (t > 0);


    std::printf("dec %lld = bin %s\n", num, &bitstr[i + 1]);

    return 0;

И это условие

( ( num == LLONG_MAX || num == LLONG_MIN ) && errno == ERANGE )

сократить до errno == ERANGE, поскольку LLONG_MAX или LLONG_MIN может быть возвращено функцией во вполне штатной ситуации (ну ввели такое число!), а вот флаг ERANGE — показателен.

А для 64-битных чисел, судя по всему, проверка на ввод отрицательного числа работать не будет.

PS. По большому счёту, ограничение на ввод отрицательных чисел в условии задачи — лишнее. Оно порождает неоднозначность. Что такое 0xffff? Для short — это -1, я для int — это 65535. Если мы работаем в контексте short, то максимальное положительное число будет 0x7fff, а не 0xffff. Аналогично и для 4- и 8-байтовых чисел.

По большому счёту, ограничение на ввод отрицательных чисел в условии
задачи — лишнее.

Я так не считаю. Перевод десятичного отрицательного числа в двоичную систему счисления происходит по другому принципу и если в программе не будет проверки, то результат будет не верным.

porshe, в первой вашей реализации мне, как и Cranium, не понравились нули, которые предшествуют бинарному числу. Они не значащие, поэтому их можно отбросить.
Так же, как в первой, так и во второй реализациях выполняется общая проверка, как для отрицательных чисел, так и для выхода за пределы n-байтового числа. В ТЗ это два разных пункта.
Программы написаны под конкретное количество байтов и трудно модифицируемы.
Вторая реализация явно не вписывается в категорию лаконичных :)

Хм... Все числа, и положительные, и отрицательные в компьютере хранятся в двоичном представлении. Если мы визуализируем это двоичное внутреннее представление (т.е. переводим в текстовый вид), то какая, на хрен, разница, положительное число или отрицательное?

Перевод десятичного отрицательного числа в двоичную систему счисления происходит по другому принципу

Согласен. Но мы-то переводим, фактически, из двоичной системы в двоичную. А не из десятичной.

и если в программе не будет проверки, то результат будет не верным.

Какой результат будет неверным? Результат визуализации внутреннего представления числа?

Или ты хочешь пойти «своим путём» и представить -5 (десятичное) как -101 (двоичное)?

Или ты хочешь пойти «своим путём» и представить -5 (десятичное) как
-101 (двоичное)?

Нет. Просто 2-х байтовое число -5 внутренне представлено 1111111111111011, а 101 это двоичное представление числа 5. Поэтому, проверка «результата внутреннего представления чисел» на отрицательное значение, в программе должна присутствовать.

Вот моя реализация данной задачи для однобайтового числа(при желании легко можно изменить для 2-х, 4-х и 8-ми байтовых чисел):

// программа перевода положительных десятичных чисел в двоичные

#include <iostream>
#include <cmath>                             // pow()

typedef long long LL;                        // псевдоним для long long

const int bits = 8;                          // кол-во бит в числе (число == 1 байт)

int main()
{
    LL dec;                                  // десятичное число

    std::cout << "Enter an positive " << bits / 8 << " bytes integer: ";
    (std::cin >> dec).get();

    int counterBits = 0;                     // счетчик разрядов
    bool binary[::bits] = {0};               // массив для представления бинарного числа (по умолчанию 0)

    if (dec >= 0) {                          // если число >= 0 ...
        if (dec <= pow(2, ::bits) - 1) {     // ... проверить не превышает ли число кол-ва байтов

            std::cout << dec << " in a binary notation: ";

            do {                             // перевести десятичное число в бинарное
                binary[counterBits++] = dec % 2;
                dec /= 2;
            } while (dec);

            while (counterBits)              // массив отобразить в обратном порядке
                std::cout << binary[--counterBits];
        }
        else
            std::cout << "The integer should be in a range from 0 to " << pow(2, ::bits) - 1 << ".\n";
    }
    else
        std::cout << "You entered a negative integer.\n";

    std::cin.get();

    return 0;
}

Что-о я не понял ни предпосылки, ни, тем более, вывода:

Просто 2-х байтовое число -5 внутренне представлено 1111111111111011, а 101 это двоичное представление числа 5. Поэтому, проверка «результата внутреннего представления чисел» на отрицательное значение, в программе должна присутствовать.

А твоя программа с 8-байтовыми (long long int) числами будет работать? Сомнения меня гложут. Но проверять сейчас времени нет. Основной вопрос в проверке уместится ли вводимое (не введённое!) число в доступное количество байт.

Что будет, если на вход программы подать число, состоящее из 79 единиц? Полагаю, что выражение (std::cin >> dec).get() даст своеобразный результат, который не будет иметь ничего общего с числом, которое хотели ввести.

#include <iostream> 
#include <conio.h>
//Для ввода и вывода
// Ибо использовать printf и scanf -- мазохизм
inline void cin_cure()
{
    std::cout << "You must enter a whole number.\n";
    std::cin.sync();
    std::cin.clear();
}
bool bad_int(int& num)
{
    (std::cin >> num).get();
    if (std::cin.good())
        if (num < 0)
            std::cerr << "Error. Value cannot be less then 0.\n";
        else
            return false;
    else
        cin_cure();
    return true;
}
void dec_to_bin(int num)
{
    if (num / 2 >= 1)
        if (num % 2 == 0)
            dec_to_bin(num / 2);
        else
            dec_to_bin((num - 1) / 2);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    do
    {
        while (bad_int(num));
        std::cout << num << std::endl;
        dec_to_bin(num);
        std::cout << "\nExit?(Y/y) ";
        exit = _getch();
    } while (exit != 'Y' && exit != 'y');
}

Как вам такой код? Работает с большими числами прекрасно

#include <iostream> 
#include <conio.h>
inline void cin_cure()
{
    std::cout << "You must enter a whole number.\n";
    std::cin.sync();
    std::cin.clear();
}
bool bad_int(int& num)
{
    (std::cin >> num).get();
    if (std::cin.good())
        if (num < 0)
            std::cerr << "Error. Value cannot be less then 0.\n";
        else
            return false;
    else
        cin_cure();
    return true;
}
void dec_to_bin(int num)
{
    if (num / 2 >= 1)
        if (num % 2 == 0)
            dec_to_bin(num / 2);
        else
            dec_to_bin((num - 1) / 2);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    do
    {
        while (bad_int(num));
        std::cout << "dec = " << num << std::endl << "bin = ";
        dec_to_bin(num);
        std::cout << "\nExit?(Y/y) ";
        exit = _getch();
    } while (exit != 'Y' && exit != 'y');
}

ВОТ теперь я точно все откорректировал!

#include <iostream> 
#include <conio.h>
inline void cin_cure()
{
    std::cerr << "Error. You must enter a whole number.\n Range -2,147,483,648 to 2,147,483,647\n";
    std::cin.sync();
    std::cin.clear();
}
bool bad_int(int& num)
{
    std::cout << "dec = ";
    (std::cin >> num).get();
    if (std::cin.good())
        if (num < 0)
            std::cerr << "Error. Number cannot be less than 0.\n";
        else
            return false;
    else
        cin_cure();
    return true;
}
void dec_to_bin(int num)
{
    if (num / 2 >= 1)
        if (num % 2 == 0)
            dec_to_bin(num / 2);
        else
            dec_to_bin((num - 1) / 2);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    std::cout << "Input whole number. Range -2,147,483,648 to 2,147,483,647\n";
    do
    {
        while (bad_int(num));
        std::cout << "bin = ";
        dec_to_bin(num);
        std::cout << "\nExit?(Y/y) ";
        exit = _getch();
        std::cout << '\n';
    } while (exit != 'Y' && exit != 'y');
}

Четвертый раз самый совершенный

#include <iostream> 
#include <conio.h>
inline void cin_cure()
{
    std::cerr << "Error. You must enter a whole number.\n Range 0 to 2,147,483,647\n";
    std::cin.sync();
    std::cin.clear();
}
bool bad_int(int& num)
{
    std::cout << "dec = ";
    (std::cin >> num).get();
    if (num >= 0)
       return false;
    cin_cure();
    return true;
}
void dec_to_bin(int num)
{
    if (num / 2 >= 1)
        if (num % 2 == 0)
            dec_to_bin(num / 2);
        else
            dec_to_bin((num - 1) / 2);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    std::cout << "Input whole number. Range 0 to 2,147,483,647\n";
    do
    {
        while (bad_int(num));
        std::cout << "bin = ";
        dec_to_bin(num);
        std::cout << "\nExit?(Y/y) ";
        exit = _getch();
        std::cout << '\n';
    } while (exit != 'Y' && exit != 'y');
}

Пятый, стопудовый

#include <iostream> 
#include <conio.h>
inline void cin_cure()
{
    std::cerr << "Error. You must enter a whole number.\n Range 0 to 2,147,483,647\n";
    std::cin.sync();
    std::cin.clear();
}
bool bad_int(int& num)
{
    std::cout << "dec = ";
    (std::cin >> num).get();
    if (std::cin.good() && num >= 0)
       return false;
    cin_cure();
    return true;
}
void dec_to_bin(int num)
{
    if (num / 2 >= 1)
        if (num % 2 == 0)
            dec_to_bin(num / 2);
        else
            dec_to_bin((num - 1) / 2);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    std::cout << "Input whole number. Range 0 to 2,147,483,647\n";
    do
    {
        while (bad_int(num));
        std::cout << "bin = ";
        dec_to_bin(num);
        std::cout << "\nExit?(Y/y) ";
        exit = _getch();
        std::cout << '\n';
    } while (exit != 'Y' && exit != 'y');
}

напоминало рукопись композитора Франца Листа, где на первой странице указано играть «быстро», на второй-«очень быстро», на третьей-«гораздо быстрее», на четвертой-«быстро как только возможно» и все-таки на пятой — «еще быстрее» (c) И.Ильф, Е.Петров «Золотой телёнок»

Илья, давай ты определись, как из вариантов действительно правильный. А остальные просто удалим дабы не раздувать топик.

  1. Илья, ты зачем кусок кода вынес в функцию inline cin_cure()? Чем он тебе мешал в месте вызова этой функции?

  2. Тебе не кажется, что bool bad_int(int& num) {...} и while (bad_int(num)); выглядит как-то неуклюже? Мне кажется, что было бы логичнее цикл засунуть в функцию, а из функции возвращать полученное и проверенное число. За одно избавились бы от побочного эффекта работы функции (изменение значения переменной во внешней области видимости).

  3. Я чего-то не понял магии в функции dec_to_bin(int num). Вот у Cranium'а мне все прозрачно и понятно. А здесь ты намутил... Может расскажешь?

  4. Мне кажется, что здесь

    (std::cin >> num).get();
    if (std::cin.good() && num >= 0)  // <-----

проверять поток уже не имеет смысла: после ввода числа (здесь проверка наверное имела бы смысл) идет операция ввода символа конца строки — будет всегда good.

ЗЫ. Cranium, там похоже еще варианты будут )))

Cranium, ты, как инициатор, определи пожалуйста, какое решение добавляем в готовые.

Сейчас, все по порядку.

1)Я заметил. В шестой, ультра финальной версии, я поправил.
2)Ладно, да , согласен. Однако строка while (bad_int(num)); показалась мне изящной). Да и так мы сохраняем память, не делая копии. Хотя это все туманно. Я переписал.

int good_int()
{
    int num;
    for (;;)
    {
        std::cout << "\ndec = ";
        (std::cin >> num).get();
        //Если не выполнять этот код, то при вводе буквы программа ломается.
        if (!std::cin.good())
        {
            std::cin.sync();
            std::cin.clear();
        }
        else if (num >= 0)return num;
        std::cerr << "Error. " << info;
    }
}

3)Дадада. Там было не очень. Я модернизировал.

 void dec_to_bin(int num)
{
    static int k;
    k = num / 2;
    if (k >= 1)
            dec_to_bin(k);
        std::cout << num % 2;
}

Что бы не вычислять два раза num / 2 , я использовал статичную переменную.
Работает так:
например, число 3
Вызов (3)
Три разделить на два больше единицы.
Вызываем функцию с аргументом(1.5)
(тип int автоматически отбрасывает дробную часть. Получается функция с аргументом (1) )

Один разделить на два меньше нуля.
Развертываем рекурсию

2) 1%2 = 1
(Честно, я так и не понял, почему там остаток 1, но много раз проверял, выводит 1.) Вот пруф

#include <iostream>
#include <conio.h>
void main()
{
    std::cout << 1 % 2;
    _getch();
}

Пруф1

1) 3%2 = 1

Весь вывод: 11

Вот так вот)


И наконец-то 4)

Я тут вообщем так.

!std::cin.good()

Работает, если вводить символ. А дальше идет очистка битов ошибок и потока.

Вот пруф с звездочкой.

if (!std::cin.good())
        {
            std::cout << "*";
            std::cin.sync();
            std::cin.clear();
        }

Пруф2

И вот наконец-то, полная версия программы. Надеюсь тут уместна глобальная переменная
типа *char

#include <iostream> 
const char *info = "Input whole number. Range 0 to 2,147,483,647";
int good_int()
{
    int num;
    for (;;)
    {
        std::cout << "\ndec = ";
        (std::cin >> num).get();
        if (!std::cin.good())
        {
            std::cin.sync();
            std::cin.clear();
        }
        else if (num >= 0)return num;
        std::cerr << "Error. " << info;
    }
}


    void dec_to_bin(int num)
{
    static int k;
    k = num / 2;
    if (k >= 1)
            dec_to_bin(k);
        std::cout << num % 2;
}
void main()
{
    int num;
    char exit;
    std::cout << "For exit input '0'\n" << info;
    for (;;)
    {
        num = good_int();
        if (num == 0)break;
        std::cout << "bin = ";
        dec_to_bin(num);
    }
}
#include <iostream> 
const char *info = "Input whole number. Range 0 to 2,147,483,647";
int good_int()
{
    int num;
    for (;;)
    {
        std::cout << "\ndec = ";
        (std::cin >> num).get();
        if (!std::cin.good())
        {
            std::cin.sync();
            std::cin.clear();
        }
        else if (num >= 0)return num;
        std::cerr << "Error. " << info;
    }
}
void dec_to_bin(int num)
{
    static int k;
    k = num / 2;
    if (k >= 1)
        dec_to_bin(k);
    std::cout << num % 2;
}
void main()
{
    int num;
    std::cout << "For exit input '0'\n" << info;
    for (;;)
    {
        num = good_int();
        if (num == 0)break;
        std::cout << "bin = ";
        dec_to_bin(num);
    }
}

Уууупс, забыл там удалить char exit. Вот вот вот

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.