Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Calculator

.cpp
Скачиваний:
0
Добавлен:
19.06.2023
Размер:
21.68 Кб
Скачать
#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;
}
Соседние файлы в предмете Программирование