Добавил:
jetu
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Calculator
.cpp#include <iostream>
#include <conio.h>
#include <fcntl.h>
#include <io.h>
#define MAX_INPUT_NUMBER 50
#define NUMBER_SIZE 156
#define OPERATION_ADDITION 0
#define OPERATION_SUBTRACTION 1
#define OPERATION_MULTIPLICATION 2
#define OPERATION_DIVISION 3
#define KEY_BACKSPACE 8
#define KEY_TAB 9
#define KEY_ESCAPE 27
#define KEY_UP 72
#define KEY_LEFT 75
#define KEY_RIGHT 77
#define KEY_DOWN 80
#define CONTROL_KEYS 224
#define FUNC_KEYS 0
const wchar_t russian_keys[52] = { L'Ф', L'ф', L'И', L'и', L'С', L'с', L'В', L'в',
L'У', L'у', L'А', L'а', L'П', L'п', L'Р', L'р',
L'Ш', L'ш', L'О', L'о', L'Л', L'л', L'Д', L'д',
L'Ь', L'ь', L'Т', L'т', L'Щ', L'щ', L'З', L'з',
L'Й', L'й', L'К', L'к', L'Ы', L'ы', L'Е', L'е',
L'Г', L'г', L'М', L'м', L'Ц', L'ц', L'Ч', L'ч',
L'Н', L'н', L'Я', L'я' };
// Преобразование десятичного числа в цифру
char to_digit(short number) {
if (number >= 0 && number <= 9)
return char(number) + '0';
return char(number - 10) + 'A';
}
// Преобразование цифры в десятичное число
short to_number(char digit) {
if (digit >= '0' && digit <= '9')
return short(digit - '0');
return short(digit - 'A') + 10;
}
// Подсчёт цифр в числе
short digits_in_number(short* number) {
short result = NUMBER_SIZE;
for (short i = 0; i < NUMBER_SIZE; i++) {
if (number[i] != 0)
break;
else
result--;
}
return result;
}
// Вывод числа на экран с заданным количеством цифр
void printn(short* number, short digits) {
if (digits > 0)
for (short i = NUMBER_SIZE - digits; i < NUMBER_SIZE; i++) {
wprintf(L"%c", to_digit(number[i]));
}
else
wprintf(L"0");
}
// Вывод числа на экран
void printn(short* number) {
printn(number, digits_in_number(number));
}
// Вывод управления на экран
void printc(const wchar_t* key, const wchar_t* description) {
wprintf(L"\n %-3s — %s", key, description);
}
// Обнуление числа
void reset_number(short* a) {
for (short i = 0; i < NUMBER_SIZE; i++)
a[i] = 0;
}
// Сложение
void add(short*a, short*b, short *result, short radix) {
short r = 0;
for (short i = NUMBER_SIZE - 1; i >= 0; i--) {
r += a[i] + b[i];
if (r >= radix) {
result[i] = r - radix;
r = 1;
}
else {
result[i] = r;
r = 0;
}
}
}
// Прибавление единицы
void add_one(short* a, short radix) {
short r = a[NUMBER_SIZE - 1] + 1;
if (r >= radix) {
a[NUMBER_SIZE - 1] = 0;
for (short i = NUMBER_SIZE - 2; i >= 0; i--) {
if (a[i] != radix - 1) {
a[i] += 1;
break;
}
a[i] = 0;
}
}
else {
a[NUMBER_SIZE - 1] = r;
}
}
// Вычитание. Возвращает true, если число положительное, false — если отрицательное
bool sub(short* a, short* b, short* result, short radix) {
short r = 0;
for (short i = NUMBER_SIZE - 1; i >= 0; i--) {
r += a[i] - b[i];
if (r < 0) {
result[i] = r + radix;
r = -1;
}
else {
result[i] = r;
r = 0;
}
}
if (r == -1) {
sub(b, a, result, radix);
return false;
}
return true;
}
// Вычитание единицы. Возвращает true, если число положительное, false — если отрицательное.
bool sub_one(short* a, short radix) {
short r = a[NUMBER_SIZE - 1] - 1;
if (r < 0) {
a[NUMBER_SIZE - 1] = r + radix;
for (short i = NUMBER_SIZE - 2; i >= 0; i--) {
if (a[i] != 0) {
a[i] = a[i] - 1;
break;
}
a[i] = radix - 1;
if (i == 0)
return false;
}
}
else {
a[NUMBER_SIZE - 1] = r;
}
return true;
}
// Умножение
void mul(short* a, short digits_in_a, short* b, short digits_in_b, short* result, short radix) {
//reset_number(result);
short t;
for (short i = NUMBER_SIZE - 1; i >= NUMBER_SIZE - digits_in_a; i--) {
short r = 0;
for (short j = NUMBER_SIZE - 1; (j >= NUMBER_SIZE - digits_in_b) || r != 0; j--) {
short t = i + j - NUMBER_SIZE + 1;
result[t] += a[i] * b[j] + r;
r = result[t] / radix;
result[t] -= r * radix;
}
}
}
// Деление. false — деление на ноль; в остальных случаях — true
bool div(short* a, short digits_in_a, short* b, short digits_in_b, short* result, short radix) {
if (digits_in_number(b) == 0)
return false;
reset_number(result);
// Копирование части числа a в число k.
short k[NUMBER_SIZE];
reset_number(k);
for (short i = 0; i < digits_in_b; i++)
k[NUMBER_SIZE - digits_in_b + i] = a[NUMBER_SIZE - digits_in_a + i];
short digits_in_k = digits_in_b;
for (short i = NUMBER_SIZE - digits_in_a + digits_in_b; i < NUMBER_SIZE + 1; i++) {
// Деление k на b вычитанием
short type;
do {
type = sub(k, b, k, radix) ? 1 : -1;
// Проверка k на 0
if (type == 1) {
type = 0;
for (short j = NUMBER_SIZE - digits_in_k; j < NUMBER_SIZE; j++) {
if (k[j] != 0) {
type = 1;
break;
}
}
}
if (type > -1) {
result[NUMBER_SIZE - 1] += 1;
}
} while (type == 1);
// Получение остатка
if (type < 0)
sub(b, k, k, radix);
if (i < NUMBER_SIZE) {
// Смещение цифр результата влево на 1
for (short j = NUMBER_SIZE / 2 - 1; j < NUMBER_SIZE - 1; j++)
result[j] = result[j + 1];
result[NUMBER_SIZE - 1] = 0;
// Подсчёт чисел в остатке
for (short j = NUMBER_SIZE - digits_in_k; j < NUMBER_SIZE; j++) {
if (k[j] != 0) break;
digits_in_k--;
}
// Смещение цифр остатка влево на 1 и добавление следующей цифры из a
for (short j = NUMBER_SIZE - digits_in_k - 1; j < NUMBER_SIZE - 1; j++)
k[j] = k[j + 1];
digits_in_k++;
k[NUMBER_SIZE - 1] = a[i];
}
}
return true;
}
// Перевод числа в десятичную систему счисления
void to_dec(short* a, short digits_in_a, short* result, short radix_a) {
if (digits_in_a == 0)
digits_in_a = 1;
reset_number(result);
short radix_a_number[NUMBER_SIZE];
reset_number(radix_a_number);
radix_a_number[NUMBER_SIZE - 1] = radix_a % 10;
radix_a_number[NUMBER_SIZE - 2] = radix_a / 10;
short digits_in_radix_a = (radix_a_number[NUMBER_SIZE - 2] == 0) ? 1 : 2;
short preresult[NUMBER_SIZE];
short k[NUMBER_SIZE];
result[NUMBER_SIZE - 1] = a[NUMBER_SIZE - digits_in_a] % 10;
result[NUMBER_SIZE - 2] = a[NUMBER_SIZE - digits_in_a] / 10;
for (int i = 1; i < digits_in_a; i++) {
reset_number(preresult);
mul(radix_a_number, digits_in_radix_a, result, digits_in_number(result), preresult, 10);
reset_number(k);
k[NUMBER_SIZE - 1] = a[NUMBER_SIZE - digits_in_a + i] % 10;
k[NUMBER_SIZE - 2] = a[NUMBER_SIZE - digits_in_a + i] / 10;
add(k, preresult, preresult, 10);
for (short j = 0; j < NUMBER_SIZE; j++)
result[j] = preresult[j];
}
}
int main() {
short a[NUMBER_SIZE], b[NUMBER_SIZE], result[NUMBER_SIZE], dec[NUMBER_SIZE];
short digits_in_a = 0;
short digits_in_b = 0;
short radix = -1;
short radix_a = 2;
short radix_b = 2;
short cursor = 0;
short operation = 0;
short position_in_number = -1;
bool res10;
bool positive_result = true;
bool div_not_zero = true;
bool update_result = false;
bool update_menu = true;
bool quit = false;
for (short i = 0; i < NUMBER_SIZE; i++) {
a[i] = 0;
b[i] = 0;
}
_setmode(_fileno(stdout), _O_U16TEXT);
while (!quit) {
system("cls");
wprintf(L" КАЛЬКУЛЯТОР\n");
if (radix == -1)
wprintf(L"\n%3s Система счисления: 0", (cursor == 0) ? L" —>" : L"");
else
wprintf(L"\n%3s Система счисления: %d", (cursor == 0)? L" —>" : L"", radix);
wprintf(L"\n%3s Первое число: ", (cursor == 1) ? L" —>" : L"");
printn(a, digits_in_a);
if (cursor == 1 && position_in_number >= 0)
wprintf(L"\n %*c", position_in_number, '^');
wprintf(L"\n%3s Второе число: ", (cursor == 2) ? L" —>" : L"");
printn(b, digits_in_b);
if (cursor == 2 && position_in_number >= 0)
wprintf(L"\n %*c", position_in_number, '^');
wprintf(L"\n%3s Операция: %3s%3s%3s%3s",
(cursor == 3) ? L" —>" : L"",
(operation == OPERATION_ADDITION) ? L"[+]" : L"+ ",
(operation == OPERATION_SUBTRACTION) ? L"[–]" : L"– ",
(operation == OPERATION_MULTIPLICATION) ? L"[×]" : L"× ",
(operation == OPERATION_DIVISION) ? L"[÷]" : L"÷ "
);
res10 = false;
if (position_in_number == -1)
wprintf(L"\n");
wprintf(L"\n\n Результат: ");
if (radix < 2 or radix > 36)
wprintf(L"Неверно задана система счисления!");
else if (radix < radix_a)
wprintf(L"Система счисления не соответствует 1-му числу!");
else if (radix < radix_b)
wprintf(L"Система счисления не соответствует 2-му числу!");
else {
if (update_result) {
positive_result = true;
div_not_zero = true;
reset_number(result);
if (operation == OPERATION_ADDITION)
add(a, b, result, radix);
else if (operation == OPERATION_SUBTRACTION)
positive_result = sub(a, b, result, radix);
else if (operation == OPERATION_MULTIPLICATION)
mul(a, digits_in_a, b, digits_in_b, result, radix);
else if (operation == OPERATION_DIVISION)
div_not_zero = div(a, digits_in_a, b, digits_in_b, result, radix);
}
// Вывод результата
if (div_not_zero) {
if (!positive_result)
wprintf(L"–");
printn(result);
// Вывод в десятичной системе счисления
if (radix != 10) {
wprintf(L"\n\n (¹⁰) ");
to_dec(a, digits_in_a, dec, radix);
printn(dec);
wprintf(L"\n %c ",
(operation == OPERATION_ADDITION) ? L'+' :
(operation == OPERATION_SUBTRACTION) ? L'–' :
(operation == OPERATION_MULTIPLICATION) ? L'×' : L'÷'
);
to_dec(b, digits_in_b, dec, radix);
printn(dec);
wprintf(L"\n = ");
if (!positive_result)
wprintf(L"–");
to_dec(result, digits_in_number(result), dec, radix);
printn(dec);
res10 = true;
}
}
else
wprintf(L"На ноль делить нельзя!");
}
update_result = false;
// Вывод справки управления
if (!res10)
wprintf(L"\n\n\n\n\n");
else
wprintf(L"\n");
if (position_in_number == -1) {
wprintf(L"\n");
printc(L"↑/↓", L"перемещение по меню");
}
if (cursor == 0)
printc(L"Tab", L"установить как максимальное значение из систем счисления чисел");
if (cursor == 1 || cursor == 2) {
if (position_in_number == -1)
printc(L"Tab", L"режим поразрядного изменения");
else {
if ((cursor == 1 && digits_in_a > 1) || (cursor == 2 && digits_in_b > 1))
printc(L"←/→", L"выбор разряда");
else
wprintf(L"\n");
printc(L"↑/↓", L"изменение значения разряда");
printc(L"Tab", L"вернуться в меню");
}
}
if (cursor == 3)
printc(L"←/→", L"выбор операции");
printc(L"Esc", L"закрыть приложение");
// Логика управления
update_menu = false;
while (!update_menu and !update_result and !quit) {
int input = _getwch();
// Замена кириллицы на латиницу
for (short i = 0; i < 52; i++) {
if (input == russian_keys[i])
input = 'A' + i / 2;
}
switch (input)
{
case FUNC_KEYS:
_getwch();
break;
case CONTROL_KEYS:
switch (_getwch())
{
case KEY_UP:
update_menu = true;
// Режим меню
if (position_in_number == -1)
if (--cursor < 0) cursor = 3;
// Режим изменения первого числа
if (cursor == 1 && position_in_number > 0) {
short position_in_array = NUMBER_SIZE - digits_in_a + position_in_number - 1;
short value = a[position_in_array] + 1;
if (value >= radix && value >= radix_a)
value = 0;
a[position_in_array] = value;
update_result = true;
}
// Режим изменения второго числа
if (cursor == 2 && position_in_number > 0) {
short position_in_array = NUMBER_SIZE - digits_in_b + position_in_number - 1;
short value = b[position_in_array] + 1;
if (value >= radix && value >= radix_b)
value = 0;
b[position_in_array] = value;
update_result = true;
}
break;
case KEY_DOWN:
update_menu = true;
// Режим меню
if (position_in_number == -1)
if (++cursor > 3) cursor = 0;
// Режим изменения первого числа
if (cursor == 1 && position_in_number > 0) {
short position_in_array = NUMBER_SIZE - digits_in_a + position_in_number - 1;
short value = a[position_in_array] - 1;
if (value < 0) {
if (radix > radix_a)
value = radix - 1;
else
value = radix_a - 1;
}
a[position_in_array] = value;
update_result = true;
}
// Режим изменения второго числа
if (cursor == 2 && position_in_number > 0) {
short position_in_array = NUMBER_SIZE - digits_in_b + position_in_number - 1;
short value = b[position_in_array] - 1;
if (value < 0) {
if (radix > radix_b)
value = radix - 1;
else
value = radix_b - 1;
}
b[position_in_array] = value;
update_result = true;
}
break;
case KEY_LEFT:
// Режим меню: изменение операции
if (position_in_number == -1 and cursor == 3) {
if (--operation < 0)
operation = 3;
update_result = true;
}
// Режим изменения числа
if (position_in_number > 0) {
if (cursor == 1 && --position_in_number < 1) position_in_number = digits_in_a;
else if (cursor == 2 && --position_in_number < 1) position_in_number = digits_in_b;
update_menu = true;
}
break;
case KEY_RIGHT:
// Режим меню: изменение операции
if (position_in_number == -1 and cursor == 3) {
if (++operation > 3)
operation = 0;
update_result = true;
}
// Режим изменения числа
if (position_in_number > 0) {
if (cursor == 1 && ++position_in_number > digits_in_a) position_in_number = 1;
else if (cursor == 2 && ++position_in_number > digits_in_b) position_in_number = 1;
update_menu = true;
}
break;
}
break;
case KEY_BACKSPACE:
if (position_in_number == -1) {
// Стирание цифры системы счисления
if (cursor == 0) {
// Стирание второй цифры
if (radix >= 10)
radix /= 10;
// Стирание первой цифры
else
radix = -1;
update_result = true;
}
// Стирание цифры первого числа
if (cursor == 1) {
radix_a = 2;
// Стирание второй и более цифры
if (digits_in_a > 1) {
for (short i = NUMBER_SIZE - 1; i >= NUMBER_SIZE - digits_in_a; i--) {
// Смещение цифр числа вправо
a[i] = a[i - 1];
// Обновление системы счисления числа
if (radix_a < a[i] + 1)
radix_a = a[i] + 1;
}
// Обновление количество цифр числа
digits_in_a--;
update_result = true;
}
// Стирание первой цифры
else if (digits_in_a == 1) {
a[NUMBER_SIZE - 1] = 0;
digits_in_a--;
update_result = true;
}
}
// Стирание цифры второго числа
if (cursor == 2) {
radix_b = 2;
// Стирание второй и более цифры
if (digits_in_b > 1) {
for (short i = NUMBER_SIZE - 1; i >= NUMBER_SIZE - digits_in_b; i--) {
// Смещение цифр числа вправо
b[i] = b[i - 1];
// Обновление системы счисления числа
if (radix_b < b[i] + 1)
radix_b = b[i] + 1;
}
// Обновление количество цифр числа
digits_in_b--;
update_result = true;
}
// Стирание первой цифры
else if (digits_in_b == 1) {
b[NUMBER_SIZE - 1] = 0;
digits_in_b--;
update_result = true;
}
}
}
break;
case KEY_TAB:
// Переключение: режим изменения числа ←→ режим меню
if (cursor == 1 || cursor == 2) {
update_menu = true;
if (position_in_number == -1) {
if (digits_in_a == 0)
digits_in_a = 1;
if (digits_in_b == 0)
digits_in_b = 1;
position_in_number = 1;
}
else {
position_in_number = -1;
// Обновление количества цифр числа
for (short i = NUMBER_SIZE - digits_in_a; i < NUMBER_SIZE; i++)
if (a[i] != 0) break;
else digits_in_a--;
for (short i = NUMBER_SIZE - digits_in_b; i < NUMBER_SIZE; i++)
if (b[i] != 0) break;
else digits_in_b--;
// Обновление системы счисления числа
radix_a = 2;
radix_b = 2;
for (short i = NUMBER_SIZE - 1; i >= NUMBER_SIZE - digits_in_a; i--) {
if (radix_a < a[i] + 1)
radix_a = a[i] + 1;
}
for (short i = NUMBER_SIZE - 1; i >= NUMBER_SIZE - digits_in_b; i--) {
if (radix_b < b[i] + 1)
radix_b = b[i] + 1;
}
}
}
// Автоматическое задание системы счисления в соответствии со СЧ чисел
if (cursor == 0) {
if (radix_a > radix_b)
radix = radix_a;
else
radix = radix_b;
update_result = true;
}
break;
case KEY_ESCAPE:
// Выход из программы
quit = true;
break;
default:
// Режим меню
if (position_in_number == -1) {
// Ввод системы счисления
if (cursor == 0 && input >= '0' && input <= '9') {
// Ввод первой цифры
if (radix == -1 && input != '0') {
radix = to_number(input);
update_result = true;
}
// Ввод второй цифры
else if (radix > 0 and radix < 10) {
radix *= 10;
radix += to_number(input);
update_result = true;
}
}
// Ввод чисел
if ((input >= '0' && input <= '9') || (input >= 'A' && input <= 'Z') || (input >= 'a' && input <= 'z')) {
// Преобразование строчных букв в прописные
if (input >= 'a' && input <= 'z')
input -= 'a' - 'A';
// Ввод первого числа
if (cursor == 1 && digits_in_a < MAX_INPUT_NUMBER) {
if (digits_in_a != 0 || (digits_in_a == 0 && input != '0')) {
// Обновление системы счисления числа
if (radix_a < to_number(input) + 1)
radix_a = to_number(input) + 1;
// Обновление количества цифр числа
digits_in_a++;
// Смещение цифр числа влево
for (short i = NUMBER_SIZE - digits_in_a; i < NUMBER_SIZE; i++)
a[i - 1] = a[i];
// Изменение последней цифры числа на введённую
a[NUMBER_SIZE - 1] = to_number(input);
update_result = true;
}
}
// Ввод второго числа
if (cursor == 2 && digits_in_b < MAX_INPUT_NUMBER) {
if (digits_in_b != 0 || (digits_in_b == 0 && input != '0')) {
// Обновление системы счисления числа
if (radix_b < to_number(input) + 1)
radix_b = to_number(input) + 1;
// Обновление количества цифр числа
digits_in_b++;
// Смещение цифр числа влево
for (short i = NUMBER_SIZE - digits_in_b; i < NUMBER_SIZE; i++)
b[i - 1] = b[i];
// Изменение последней цифры числа на введённую
b[NUMBER_SIZE - 1] = to_number(input);
update_result = true;
}
}
}
}
break;
}
}
}
return 0;
}
Соседние файлы в предмете Программирование