Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лаба «ИССЛЕДОВАНИЕ ВНУТРЕННЕГО ПРЕДСТАВЛЕНИЯ РАЗЛИЧНЫХ ФОРМАТОВ ДАННЫХ» ЭВМ.docx
Скачиваний:
0
Добавлен:
08.07.2025
Размер:
1.58 Mб
Скачать

МИНОБРНАУКИ РОССИИ

Санкт-Петербургский государственный

электротехнический университет

«ЛЭТИ» им. В.И. Ульянова (Ленина)

Кафедра вычислительной техники

отчет

по лабораторной работе №1

по дисциплине «Организация ЭВМ и систем»

Тема: «исследование внутреннего представления различных форматов данных»

Студенты гр. 3352

Преподаватель

Санкт-Петербург

2024

Задачи

  1. Разработать алгоритм ввода с клавиатуры значения типа unsigned int или long double и показать на экране их внутреннее представление в двоичной системе счисления.

  2. Написать и отладить программу на языке С++, реализующую разработанный алгоритм.

  3. Дополнить алгоритм блоками для циклического сдвига в заданном направлении внутри группы разрядов; направление сдвига, размер группы разрядов и младший разряд в группе вводятся с клавиатуры.

Блок-схема алгоритма

Функция longDoubleToBinary

Функция isValidLongDouble

Функция binaryToLongDouble

Функция RotateInt / RotateDouble (изменяется только размер на входе)

Функция Main

Текст программы

#include <iostream>

#include <array>

#include <bitset>

#include <cstring>

#include <cmath>

#include <limits>

#include <string>

using namespace std;

bool isValidLongDouble(const string& input) {

char* end;

// Попытка преобразования строки в long double

strtold(input.c_str(), &end);

// Проверка, не осталась ли часть строки, которая не была преобразована

return end != input.c_str() && *end == '\0';

}

void longDoubleToBinary(long double number2, bool binaryArray[64]) {

// Преобразование long double в unsigned long long для хранения битов

unsigned long long* ptr = reinterpret_cast<unsigned long long*>(&number2);

// Получаем 64 бита

unsigned long long num = *ptr;

// Заполнение массива

for (int i = 0; i < 64; ++i) {

binaryArray[63 - i] = (num >> i) & 1; // Заполнение от младшего к старшему

}

}

long double binaryToLongDouble(bool binaryArray[64]) {

unsigned long long num = 0;

// Преобразование из двоичного массива в число

for (int i = 0; i < 64; ++i) {

num <<= 1; // Сдвиг влево

num |= binaryArray[i]; // Добавление бита

}

// Преобразование обратно в long double

return *reinterpret_cast<long double*>(&num);

}

void RotateInt(int binary[32], int shift, int startBit, int groupSize, char direction) {

int leftBord = 32 - (groupSize + startBit);

int rightBord = leftBord + groupSize - 1;

int* mini = new int[groupSize];

int left = leftBord;

for (int i = 0; i < groupSize; i++) {

mini[i] = binary[left];

left++;

}

cout << " Группа разрядов для циклического сдвига: ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

int shi = 0;

if (shift == groupSize) {

cout << "\n Количетсво разрядов для сдвига равно группе, поэтому двоичная запись не меняется";

}

if (shift > groupSize) {

shi = shift % groupSize;

cout << "\n Количество разрядов для сдвига больше, чем группа разрядов, поэтому делаем сдвиг на " << shift << " % " << groupSize << " = " << shi;

}

if (shift < groupSize) {

shi = shift;

//cout << "\n Количество разрядов для сдвига меньше, чем группа разрядов, поэтому делаем сдвиг на " << shi;

}

int* micro = new int[shi];

// ДЛЯ ЛЕВОГО СДВИГА

int j = 0;

if (direction == 'l') {

for (int i = 0; i < shi; i++) {

micro[i] = mini[j];

j++;

}

//cout << "\n массив micro: ";

//for (int i = 0; i < shi; i++) {

// cout << micro[i];

//}

for (int i = 0; i < (groupSize - shi); i++) {

mini[i] = mini[i + shi];

}

for (int i = 0; i < shi; i++) {

mini[groupSize - shi + i] = micro[i];

}

cout << "\n Группа разрядов после циклического сдвига влево на " << shi << ": ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

}

// ДЛЯ ПРАВОГО СДВИГА

int k = 0;

if (direction == 'r') {

for (int i = 0; i < shi; i++) {

micro[i] = mini[k + groupSize - shi];

k++;

}

//cout << "\n массив micro: ";

//for (int i = 0; i < shi; i++) {

// cout << micro[i];

//}

for (int i = 0; i < (groupSize - shi); i++) {

mini[groupSize - 1 - i] = mini[groupSize - shi - i - 1];

}

for (int i = 0; i < shi; i++) {

mini[i] = micro[i];

}

cout << "\n Группа разрядов после циклического сдвига вправо на " << shi << ": ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

}

delete[]micro;

int e = 0;

for (int i = leftBord; i < (leftBord + groupSize); i++) {

binary[i] = mini[e];

e++;

}

delete[]mini;

cout << "\n\n Результат:\n Двоичное представление числа после сдвига: ";

for (int i = 0; i < 32; i++) {

cout << binary[i];

}

unsigned int decimal = 0;

// Перевод двоичного числа в десятичное

for (int i = 0; i < 32; i++) {

if (binary[i] == 1) {

decimal += static_cast<unsigned int>(pow(2, 31 - i));

}

}

cout << "\n Десятичное представление числа после сдвига: " << decimal << endl;

}

void RotateDouble(bool binaryArray[64], int shift, int startBit, int groupSize, char direction) {

int leftBord = 64 - (groupSize + startBit);

int rightBord = leftBord + groupSize - 1;

int* mini = new int[groupSize];

int left = leftBord;

for (int i = 0; i < groupSize; i++) {

mini[i] = binaryArray[left];

left++;

}

cout << " Группа разрядов для циклического сдвига: ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

int shi = 0;

if (shift == groupSize) {

cout << "\n Количетсво разрядов для сдвига равно группе, поэтому двоичная запись не меняется";

}

if (shift > groupSize) {

shi = shift % groupSize;

cout << "\n Количество разрядов для сдвига больше, чем группа разрядов, поэтому делаем сдвиг на " << shift << " % " << groupSize << " = " << shi;

}

if (shift < groupSize) {

shi = shift;

//cout << "\n Количество разрядов для сдвига меньше, чем группа разрядов, поэтому делаем сдвиг на " << shi;

}

int* micro = new int[shi];

// ДЛЯ ЛЕВОГО СДВИГА

int j = 0;

if (direction == 'l') {

for (int i = 0; i < shi; i++) {

micro[i] = mini[j];

j++;

}

//cout << "\n массив micro: ";

//for (int i = 0; i < shi; i++) {

// cout << micro[i];

//}

for (int i = 0; i < (groupSize - shi); i++) {

mini[i] = mini[i + shi];

}

for (int i = 0; i < shi; i++) {

mini[groupSize - shi + i] = micro[i];

}

cout << "\n Группа разрядов после циклического сдвига влево на " << shi << ": ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

}

int k = 0;

if (direction == 'r') {

for (int i = 0; i < shi; i++) {

micro[i] = mini[k + groupSize - shi];

k++;

}

//cout << "\n массив micro: ";

//for (int i = 0; i < shi; i++) {

// cout << micro[i];

//}

for (int i = 0; i < (groupSize - shi); i++) {

mini[groupSize - 1 - i] = mini[groupSize - shi - i - 1];

}

for (int i = 0; i < shi; i++) {

mini[i] = micro[i];

}

cout << "\n Группа разрядов после циклического сдвига вправо на " << shi << ": ";

for (int i = 0; i < groupSize; i++) {

cout << mini[i];

}

}

delete[]micro;

int e = 0;

for (int i = leftBord; i < (leftBord + groupSize); i++) {

binaryArray[i] = mini[e];

e++;

}

delete[]mini;

cout << "\n\n Результат:\n Двоичное представление числа после сдвига: ";

for (int i = 0; i < 64; i++) {

cout << binaryArray[i];

}

// Преобразование обратно в десятичную систему

long double convertedNumber = binaryToLongDouble(binaryArray);

cout << " Преобразованное обратно число: " << convertedNumber << endl;

}

int main() {

setlocale(LC_ALL, "ru");

bool validInput = false;

char direction;

int shift, startBit, groupSize;

int Case = -1;

cout << "\n Добрый день! Давайте начнём работу :)";

while (Case != 0)

{

cout << "\n _________________________________________";

cout << "\n | Меню: |";

cout << "\n | * Чтобы закончить работу, выберите 0 |";

cout << "\n | * Чтобы ввести unsigned int, выберите 1 |";

cout << "\n | * Чтобы ввести long double, выберите 2 |";

cout << "\n -----------------------------------------";

cout << "\n\n Ввод: ";

cin >> Case;

if (Case < 0) {

cout << "\n Это некорректный номер!";

continue;

}

if (Case > 2) {

cout << "\n Это некорректный номер!";

continue;

}

if (Case == 0) {

cout << "\n У нас получилось! Мы молодцы! Работа закончена. До свидания! \n\n";

break;

}

if ((Case == 1) || (Case == 2)) {/*

cout << "\n Выбрана команда " << Case;*/

if (Case == 1) {

while (Case == 1) {

cout << "\n ______________________________________________________________";

cout << "\n |* Чтобы вернуться в Меню, выберите 0 |";

cout << "\n |* Чтобы перевести unsigned int в двоичную систему, выберите 1 |";

cout << "\n --------------------------------------------------------------";

cout << "\n\n Ввод: ";

int Case_1 = -1;

cin >> Case_1;

if ((Case_1 < 0) || (Case_1 > 1)) {

cout << "\n Это некорректный номер!\n";

continue;

}

if (Case_1 == 1) {

unsigned int number;

const int BINARY_SIZE = 32;

int binary[BINARY_SIZE] = { 0 }; // Массив для хранения двоичного представления числа

// Запрашиваем ввод

cout << " Пожалуйста, введите целое число в диапозоне unsigned int: ";

// Проверка на ввод

while (true) {

string input;

cin >> input;

char target = '-';

int count = std:: count(input.begin(), input.end(), target);

if ((input.find('-') == 0) && (count == 1) && (input.size() > 1)) {

cout << " Ошибка: число выходит за диапазон unsigned int. Введите новое число: ";

continue;

}

try {

// Пробуем конвертировать строку в unsigned int

number = stoul(input);

break; // Если успешно, выходим из цикла

}

catch (const invalid_argument& e) {

cout << " Пожалуйста, введите корректное число: ";

}

catch (const out_of_range& e) {

cout << " Ошибка: число выходит за диапозон unsigned int. Введите новое число: ";

}

}

// Перевод в двоичную систему счисления

for (int i = 0; i < BINARY_SIZE; ++i) {

binary[BINARY_SIZE - 1 - i] = (number >> i) & 1; // Получаем каждый бит числа

}

// Вывод двоичного представления

cout << " Двоичное представление числа: ";

for (int i = 0; i < BINARY_SIZE; ++i) {

cout << binary[i];

}

cout << endl;

do {

cout << "\n Введите направление сдвига для unsigned int (l для влево, r для вправо): ";

cin >> direction;

} while (direction != 'l' && direction != 'r');

do {

cout << " Введите количество разрядов для сдвига: ";

cin >> shift;

} while (shift < 0);

do {

cout << " Введите номер младшего разряда (0-" << sizeof(unsigned int) * 8 - 1 << "): ";

cin >> startBit;

} while (startBit < 0 || startBit >= sizeof(unsigned int) * 8);

do {

cout << " Введите размер группы разрядов (1-" << (sizeof(unsigned int) * 8 - startBit) << "): ";

cin >> groupSize;

} while (groupSize < 1 || groupSize >(sizeof(unsigned int) * 8 - startBit));

RotateInt(binary, shift, startBit, groupSize, direction);

}

if (Case_1 == 0) {

cout << "\n Вы выбрали возвращение к меню\n";

break;

}

}

}

if (Case == 2) {

while (Case == 2) {

cout << "\n _____________________________________________________________";

cout << "\n |* Чтобы вернуться в Меню, выберите 0 |";

cout << "\n |* Чтобы перевести long double в двоичную систему, выберите 1 |";

cout << "\n -------------------------------------------------------------";

cout << "\n\n Ввод: ";

int Case_1 = -1;

cin >> Case_1;

if (Case_1 < 0) {

cout << "\n Это некорректный номер!\n";

continue;

}

if (Case_1 > 1) {

cout << "\n Это некорректный номер!\n";

continue;

}

if (Case_1 == 1) {

long double number2;

string input;

bool binaryArray[64];

int flag2 = 0;

// Инициализация массива на случай, если нужно будет использовать

memset(binaryArray, 0, sizeof(binaryArray));

while (flag2 != 1) {

getline(cin, input);

// Проверка на корректность ввода

if (!isValidLongDouble(input)) {

cout << " Пожалуйста, введите корректное число через запятую (пример: 12,3) : ";

continue;

}

// Преобразование строки в long double

number2 = stold(input);

// Проверка на диапазон

if (number2 < numeric_limits<long double>::min() || number2 > numeric_limits<long double>::max()) {

cout << " Ошибка: введенное число выходит за диапазон long double. Введите новое число: ";

continue;

}

// Если все проверки пройдены:

flag2 = 1;

break;

}

if (flag2 == 1) {

longDoubleToBinary(number2, binaryArray);

cout << " Двоичное представление: ";

for (bool bit : binaryArray) {

cout << bit;

}

cout << endl;

bool longDoubleDirection;

do {

cout << " Введите направление сдвига для long double (l для влево, r для вправо): ";

cin >> direction;

} while (direction != 'l' && direction != 'r');

longDoubleDirection = (direction == 'l');

do {

cout << " Введите количество разрядов для сдвига (0-" << (sizeof(long double) * 8 - 1) << "): ";

cin >> shift;

} while (shift < 0 || shift >= sizeof(long double) * 8);

do {

cout << " Введите номер младшего разряда (0-" << sizeof(long double) * 8 - 1 << "): ";

cin >> startBit;

} while (startBit < 0 || startBit >= sizeof(long double) * 8);

do {

cout << " Введите размер группы разрядов (1-" << (sizeof(long double) * 8 - startBit) << "): ";

cin >> groupSize;

} while (groupSize < 1 || groupSize >(sizeof(long double) * 8 - startBit));

RotateDouble(binaryArray, shift, startBit, groupSize, direction);

//// Преобразование обратно в десятичную систему

//long double convertedNumber = binaryToLongDouble(binaryArray);

//cout << " Преобразованное обратно число: " << convertedNumber << endl;

}

}

if (Case_1 == 0) {

cout << "\n Вы выбрали возвращение к Меню\n";

break;

}

}

}

}

}

return 0;

}

Тестовые примеры запуска программы

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

Пример 1. Число типа unsigned int

После того, как пользователь выбрал из меню пункт 1, ему предлагается ещё раз выбрать пункт из меню.

После выбора 1, пользователю предлагается ввести число типа unsigned int. При вводе комбинации различных символов программа просит ввести корректное число. Если пользователь вводит число, выходящие из диапазона, его так же просят ввести новое число, входящее в диапазон unsigned int. Как только вводится корректное число, программа выполняет перевод этого числа в двоичную запись и выводит её на экран.

Далее пользователь должен выбрать направление сдвига, количество разрядов для сдвига, номер младшего разряда и группу разрядов. После ввода данных программа выводит изменившуюся группу разрядов, полную двоичную запись нового числа и десятичное представление нового числа. Как мы видим, после сдвига число 555 изменилось на 558.

Точно так же можно выполнить сдвиг вправо.

Рассмотрим вариант, когда сдвиг происходит на количество разрядов, большее, чем группа разрядов. В этому случае сдвиг происходит на количество, равное остатку от деления количества на группу.

Рассмотрим случай, когда сдвиг не происходит. Это может произойти, когда а) пользователь ввёл 0 в «количество разрядов», б) когда количество разрядов совпало с группой.

а)

б)

Теперь вернемся в меню и выберем пункт 2.

Пример 2. Число типа long double

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

Примеры сдвигов влево и вправо.

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

Случаи, когда сдвигов не происходит.

Чтобы вернуться к меню, пользователю достаточно ввести 0 после обработки числа, после чего он может выбрать число другого типа.

Для завершения работы пользователю нужно ввести 0 в главном меню.