#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;
}
Мне кажется, ты немного перемудрил. Последний кусок можно написать проще:
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) И.Ильф, Е.Петров «Золотой телёнок»
Илья, давай ты определись, как из вариантов действительно правильный. А остальные просто удалим дабы не раздувать топик.
Фтьiкай
Илья, ты зачем кусок кода вынес в функцию inline cin_cure()? Чем он тебе мешал в месте вызова этой функции?
Тебе не кажется, что bool bad_int(int& num) {...} и while (bad_int(num)); выглядит как-то неуклюже? Мне кажется, что было бы логичнее цикл засунуть в функцию, а из функции возвращать полученное и проверенное число. За одно избавились бы от побочного эффекта работы функции (изменение значения переменной во внешней области видимости).
Я чего-то не понял магии в функции dec_to_bin(int num). Вот у Cranium'а мне все прозрачно и понятно. А здесь ты намутил... Может расскажешь?
Мне кажется, что здесь
(std::cin >> num).get();
if (std::cin.good() && num >= 0) // <-----
проверять поток уже не имеет смысла: после ввода числа (здесь проверка наверное имела бы смысл) идет операция ввода символа конца строки — будет всегда good.
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.) Вот пруф
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Согласен, погорячился с длинной арифметикой :\
Вызвать
itoa( toBin, binstr, 2 )
:DС
strtoll
всё действительно становится намного проще:porshe, твоя программа для 0 не выводит двоичного представления.
Простая проверка на 0, полагаю, должна решить эту проблему. Можно ещё в цикле условие выполнения на
t >= 0
поменять.Мне кажется, ты немного перемудрил. Последний кусок можно написать проще:
И это условие
сократить до
errno == ERANGE
, поскольку LLONG_MAX или LLONG_MIN может быть возвращено функцией во вполне штатной ситуации (ну ввели такое число!), а вот флаг ERANGE — показателен.А для 64-битных чисел, судя по всему, проверка на ввод отрицательного числа работать не будет.
PS. По большому счёту, ограничение на ввод отрицательных чисел в условии задачи — лишнее. Оно порождает неоднозначность. Что такое 0xffff? Для short — это -1, я для int — это 65535. Если мы работаем в контексте short, то максимальное положительное число будет 0x7fff, а не 0xffff. Аналогично и для 4- и 8-байтовых чисел.
Я так не считаю. Перевод десятичного отрицательного числа в двоичную систему счисления происходит по другому принципу и если в программе не будет проверки, то результат будет не верным.
porshe, в первой вашей реализации мне, как и Cranium, не понравились нули, которые предшествуют бинарному числу. Они не значащие, поэтому их можно отбросить.
Так же, как в первой, так и во второй реализациях выполняется общая проверка, как для отрицательных чисел, так и для выхода за пределы n-байтового числа. В ТЗ это два разных пункта.
Программы написаны под конкретное количество байтов и трудно модифицируемы.
Вторая реализация явно не вписывается в категорию лаконичных :)
Хм... Все числа, и положительные, и отрицательные в компьютере хранятся в двоичном представлении. Если мы визуализируем это двоичное внутреннее представление (т.е. переводим в текстовый вид), то какая, на хрен, разница, положительное число или отрицательное?
Согласен. Но мы-то переводим, фактически, из двоичной системы в двоичную. А не из десятичной.
Какой результат будет неверным? Результат визуализации внутреннего представления числа?
Или ты хочешь пойти «своим путём» и представить -5 (десятичное) как -101 (двоичное)?
Нет. Просто 2-х байтовое число -5 внутренне представлено 1111111111111011, а 101 это двоичное представление числа 5. Поэтому, проверка «результата внутреннего представления чисел» на отрицательное значение, в программе должна присутствовать.
Вот моя реализация данной задачи для однобайтового числа(при желании легко можно изменить для 2-х, 4-х и 8-ми байтовых чисел):
Что-о я не понял ни предпосылки, ни, тем более, вывода:
А твоя программа с 8-байтовыми (long long int) числами будет работать? Сомнения меня гложут. Но проверять сейчас времени нет. Основной вопрос в проверке уместится ли вводимое (не введённое!) число в доступное количество байт.
Что будет, если на вход программы подать число, состоящее из 79 единиц? Полагаю, что выражение
(std::cin >> dec).get()
даст своеобразный результат, который не будет иметь ничего общего с числом, которое хотели ввести.Как вам такой код? Работает с большими числами прекрасно
ВОТ теперь я точно все откорректировал!
Четвертый раз самый совершенный
Пятый, стопудовый
Илья, давай ты определись, как из вариантов действительно правильный. А остальные просто удалим дабы не раздувать топик.
Илья, ты зачем кусок кода вынес в функцию
inline cin_cure()
? Чем он тебе мешал в месте вызова этой функции?Тебе не кажется, что
bool bad_int(int& num) {...}
иwhile (bad_int(num));
выглядит как-то неуклюже? Мне кажется, что было бы логичнее цикл засунуть в функцию, а из функции возвращать полученное и проверенное число. За одно избавились бы от побочного эффекта работы функции (изменение значения переменной во внешней области видимости).Я чего-то не понял магии в функции
dec_to_bin(int num)
. Вот у Cranium'а мне все прозрачно и понятно. А здесь ты намутил... Может расскажешь?Мне кажется, что здесь
проверять поток уже не имеет смысла: после ввода числа (здесь проверка наверное имела бы смысл) идет операция ввода символа конца строки — будет всегда good.
ЗЫ. Cranium, там похоже еще варианты будут )))
Cranium, ты, как инициатор, определи пожалуйста, какое решение добавляем в готовые.
Сейчас, все по порядку.
1)Я заметил. В шестой, ультра финальной версии, я поправил.
2)Ладно, да , согласен. Однако строка
while (bad_int(num));
показалась мне изящной). Да и так мы сохраняем память, не делая копии. Хотя это все туманно. Я переписал.3)Дадада. Там было не очень. Я модернизировал.
Что бы не вычислять два раза num / 2 , я использовал статичную переменную.
Работает так:
например, число 3
Вызов (3)
Три разделить на два больше единицы.
Вызываем функцию с аргументом(1.5)
(тип int автоматически отбрасывает дробную часть. Получается функция с аргументом (1) )
Один разделить на два меньше нуля.
Развертываем рекурсию
2) 1%2 = 1
(Честно, я так и не понял, почему там остаток 1, но много раз проверял, выводит 1.) Вот пруф
1) 3%2 = 1
Весь вывод: 11
Вот так вот)
И наконец-то 4)
Я тут вообщем так.
Работает, если вводить символ. А дальше идет очистка битов ошибок и потока.
Вот пруф с звездочкой.
И вот наконец-то, полная версия программы. Надеюсь тут уместна глобальная переменная
типа *char
Уууупс, забыл там удалить char exit. Вот вот вот