Консультация № 184002
11.09.2011, 09:17
146.20 руб.
0 11 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:Помогите пожалуйста написать объектно-ориентированную программу. OS Windows XP, Borland C++ Builder 6,2006, Visual Studio 2005. Код прокомментировать. Условие задачи:
1. Разработать класс "двоичное число" в соответствии со следующим заданием:
Состояние класса-
Целое двоичное число в прямом коде со знаком определяется его длиной (кол-во цифр в числе, например, до 74) и массивом значений двоичных цифр (типа char). Число со знаком хранится в прямом коде. При выполнении арифметических операций использовать дополнительный код. Память под массив выделяется статически, во время компиляции, и задается массивом фиксированного предельного размера.
Протокол класса-
Определяет возможности создания и инициализации экземпляров класса и правила их использования (методы класса).
Предусмотреть следующие возможности:
пустой конструктор для инициализации экземпляров и массивов экземпляров класса по умолчанию;
создание экземпляров класса с инициализацией значением целого числа типа long;
создание экземпляров класса с инициализацией значением числа как строки символов;
ввод экземпляров класса из входного потока и вывод их значений в выходной поток (с помощью перегруженных операторов >> и <<);
получение дополнительного кода числа (с помощью перегруженного оператора ~);
выполнение операции сложения чисел с разными знаками в дополнительном коде (с помощью перегруженного оператора +);
выполнение операции увеличения числа на единицу до использования числа (с помощью префиксной перегруженного оператора ++);
выполнение операции уменьшения числа после его использования (с помощью постфиксной перегруженного оператора --);
выполнение операции определения знака числа.
2. Проектирование класса рекомендуется начать с представления состояния класса, учитывающего заданные операции, а затем реализации конструкторов и перегруженного оператора вывода. Для отладки и исчерпывающего тестирования других методов разработанного класса реализовать диалоговую программу, которая позволяет вводить параметры, отлаживаемых методов. Для обработки ошибочных ситуаций использовать механизм исключительных ситуаций.
3. Написать прикладную программу, использующую разработанный класс.

Обсуждение

Неизвестный
11.09.2011, 23:39
общий
Адресаты:
Не могу понять, что такое "прямой код" и "дополнительный код"?..
И ещё: предполагает ли данный класс реализацию длинной арифметики (т.е. все операции типа сложения делаются вручную) или можно ограничиться числами, влезающими в тип long?
давно
Посетитель
276566
297
12.09.2011, 09:12
общий
Здравствуйте! Уточню сегодня по поводу прямого и дополнительного кодов.
давно
Посетитель
276566
297
12.09.2011, 23:43
общий
По поводу прямого и дополнительного кода. Если мы вводим число 5 то в памяти оно отображается как 101 в ПК и ДК. Ответ арифметических операций в памяти отображается в ПК. Например: 5(0.00101 в ПК И ДК), -3 (1.00011 в ПК И 11101 в ДК), если сложить 5 и -3 то получится 2 (00010 в ПК и ДК). Если исп. тип long, то числа можно вводить как нормальные числа типа 5,6,7 и т.д., если char то лучше в виде 101, 110,111 и т.д. В памяти и в ответе числа должны отображаться в прямом коде, а в операциях в дополнительном коде.
Поскольку память статическая, то максимальное количество цифр в числе 74.
Неизвестный
15.09.2011, 17:06
общий
Адресаты:
Завтра постараюсь выложить.
давно
Посетитель
276566
297
18.09.2011, 17:18
общий
Здравствуйте! Скажите когда вы примерно выложите код.
Неизвестный
18.09.2011, 23:23
общий
Адресаты:
Да, простите, не получилось в пятницу, а в выходные была занята. Завтра вечером или, самое позднее, во вторник.
Неизвестный
19.09.2011, 21:09
общий
это ответ
Здравствуйте, Magma!
Примерно так. Все математические (вычитание и сложение) операции происходят через дополнительный код. Благодаря этому они сводятся к общему виду. Особенности сложения в дополнительном коде можно посмотреть здесь.
Несмотря на то, что число хранится в массиве char, я храню там просто 0 и 1 (числа), а не '0' и '1' (символы), преобразовывая к символам только для вывода на экран. Для манипуляций с массивом часто используются функции memset и memcpy.
Пример использования класса:
Код:
#include <conio.h>
#include <stdlib.h>
#include "Binary.h"


int _tmain(int argc, _TCHAR* argv[])
{ //пример
try {
CBinary a (2), b(12);
cin >> a;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "a-b = " << (a-b) << endl;
cout << "a+b = " << (a+b) << endl;
cout << "a++ = " << (++a) << endl;
cout << "a-- = " << (--a) << endl;
cout << "~a = " << (~a) << endl;
} catch (char* ex) {
cout << ex;
}
getch(); //ожидаем пользователя
return 0;
}

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

Приложение:
//Binary.h
#pragma once
#include <iostream>
using namespace std;

class CBinary
{
static const int len = 74; //длина числа
char number [len]; //число
char user_extra [len]; //дополнительный код для оператора ~
char sign; //знак
public:
CBinary (); //конструктор по умолчанию
CBinary (const CBinary &bin); //конструктор копирования
CBinary (long data); //конструктор из числа
CBinary (const char* data); //конструктор из строки

CBinary& operator= (CBinary b); //оператор присваивания

CBinary& operator+= (CBinary b);
CBinary& operator-= (CBinary b);
CBinary& operator++ ();
CBinary& operator-- ();
const char* operator~ (); //получение дополнительного кода

friend CBinary operator+ (CBinary &b1, CBinary &b2);
friend CBinary operator- (CBinary &b1, CBinary &b2);

friend ostream& operator << (ostream& str, CBinary& b); //вывод
friend istream& operator >> (istream& str, CBinary& b); //ввод

bool IsNegative (); //определение знака

private: //служебные функции
long BinaryToLong (); //преобразование в число
void LongToBinary (long data, char* out, char &sgn); //получение из 10-го числа
void BinaryFromString (char* in, char* out, char &sgn); //получение из строки
bool CheckString (char* data); //проверка строки
void ToExtraCode (char* extra, int count); //в дополнительный код с заданным числом знаков
void FromExtraCode (char* extra, int count); //из дополнительного кода с заданным числом знаков
void Summ (char* slag1, char* slag2, char* res); //нахождение суммы двух чисел
void ToString (char* str); //преобразовать текущее число к строке
void ToString (char* str, char* bin); //преобразовать передаваемое число к строке
int GetCount (); //определить число значащих цифр
int GetCount (char* bin); //то же, но для заданного числа
};

//Binary.cpp
#include "StdAfx.h"
#include "Binary.h"
#include <string.h>
#include <math.h>

CBinary::CBinary()
{
memset (number, 0, sizeof(char)*len);
sign = 0;
}

CBinary::CBinary (const CBinary &bin)
{
memcpy (number, bin.number, sizeof(char)*len);
sign = bin.sign;
}

CBinary::CBinary (long data)
{
sign = 0;
LongToBinary (data, number, sign);
}

CBinary::CBinary (const char* data)
{
sign = 0;
char* dt = new char[strlen(data)+1];
strcpy (dt, data);
if (!CheckString (dt)) memset (number, 0, sizeof(char)*len);
else BinaryFromString (dt, number, sign);
}

bool IsNegative ()
{
return sign;
}

long CBinary::BinaryToLong ()
{
long res = number[1];
for (int i=2; i<len; i++)
res = res*2 + number[i];
return res;
}

void CBinary::LongToBinary (long data, char* out, char &sgn)
{
int i = 1;
sgn = (data<0);
data = abs(data);
memset (out, 0, sizeof(char)*len);
while (data>1) {
out[len-i] = data%2;
data/=2;
i++;
}
out[len-i] = data;
}

void CBinary::BinaryFromString (char* in, char* out, char &sgn)
{
memset (out, 0, sizeof(char)*len);
int l = strlen (in);
for (int i=l-1, j=1; i>0; i--, j++)
out[len-j] = in[i]-48;
if (in[0]=='-') sgn = 1;
else if (in[0]=='+') sgn = 0;
else {
sgn = 0;
out[len-l] = in[0]-48;
}
}

bool CBinary::CheckString (char* data)
{
int l = strlen(data);
if (l>len-1) return false;
int i = 0;

while (i<l && data[i]==' ') {data[i] = '0'; i++;}
if (i==l) return false;

while (l>0 && data[l-1]==' ') l--;
if (l==0) return false;
data[l] = '\0';

if (data[i]=='+' || data[i]=='-') {
char t = data[i];
data[i] = data[0];
data[0] = t;
i++;
}

for (; i<l; i++)
if (data[i]!='1' && data[i]!='0') return false;

return true;
}

void CBinary::ToExtraCode (char* extra, int count)
{
if (!sign) {
memcpy (extra, number, sizeof(char)*len);
return;
}

memset (extra, 0, sizeof(char)*len);

for (int i = len-1, j = 0; i>=0 && j<count; i--, j++)
extra[i] = !number[i];
char one [len], res[len];
memset (one, 0, sizeof(char)*len);
one[len-1] = 1;
Summ (extra, one, res);
memcpy (extra, res, sizeof(char)*len);

extra[len-count-1] = 1;
}

void CBinary::FromExtraCode (char* extra, int count)
{
memset (number, 0, sizeof(char)*len);

sign = extra[len-count-1];
if (!sign) {
for (int i=len-1, j=0; i>=0 && j<count; i--, j++)
number[i] = extra[i];
return;
}
for (int i=len-1, j=0; i>=0 && j<count; i--, j++)
number[i] = !extra[i];
char one [len], res[len];
memset (one, 0, sizeof(char)*len);
one[len-1] = 1;
Summ (number, one, res);
memcpy (number, res, sizeof(char)*len);
}

void CBinary::Summ (char* slag1, char* slag2, char* res)
{
char one = 0, tmp;
memset (res, 0, sizeof(char)*len);
for (int i=len-1; i>=0; i--) {
tmp = slag1[i]+slag2[i]+one;
if (tmp>1) {
one = 1;
res[i] = tmp%2;
} else {
one = 0;
res[i] = tmp;
}
}
if (one!=0) throw ("Very big summ!");
}

CBinary& CBinary::operator= (CBinary b)
{
memcpy (number, b.number, sizeof(char)*len);
sign = b.sign;
return *this;
}

CBinary& CBinary::operator+= (CBinary b)
{
char ext1[len], ext2[len], res[len];
int c = max<int>(GetCount(), b.GetCount())+1;
if (c>=len) throw "Too big number";
ToExtraCode (ext1, c);
b.ToExtraCode (ext2, c);
int e1 = max<int>(GetCount(ext1), GetCount(ext2));
Summ (ext1, ext2, res);
FromExtraCode (res, c);
return *this;
}

CBinary& CBinary::operator-= (CBinary b)
{
b.sign = !b.sign;
*this+=b;
return *this;
}

CBinary& CBinary::operator++ ()
{
CBinary one (1);
*this+=one;
return *this;
}

CBinary& CBinary::operator-- ()
{
CBinary one (-1);
*this+=one;
return *this;
}

const char* CBinary::operator~ ()
{
char ext1[len];
ToExtraCode (ext1, GetCount());
ToString (user_extra, ext1);
return user_extra;
}

void CBinary::ToString (char* str)
{
int i = 1, j = 0;
while (i<len && number[i]==0) i++;
if (sign) {str[j]='-'; j++;}
for (; i<len; i++, j++) str[j] = number[i]?'1':'0';
if (j==0) {str[j]='0'; j++;}
str[j] = '\0';
}

void CBinary::ToString (char* str, char* bin)
{
int i = 0, j = 0;
while (i<len && bin[i]==0) i++;
for (; i<len; i++, j++) str[j] = bin[i]?'1':'0';
if (j==0) {str[j]='0'; j++;}
str[j] = '\0';
}

int CBinary::GetCount ()
{
int i = 0;
while (i<len && number[i]==0) i++;
return len-i;
}

int CBinary::GetCount (char* bin)
{
int i = 0;
while (i<len && bin[i]==0) i++;
return len-i;
}


CBinary operator+ (CBinary &b1, CBinary &b2)
{
CBinary bin (b1);
bin+=b2;
return bin;
}

CBinary operator- (CBinary &b1, CBinary &b2)
{
CBinary bin (b1);
bin-=b2;
return bin;
}

ostream& operator << (ostream& str, CBinary& b)
{
char buf[b.len+2];
b.ToString(buf);
str << buf;
return str;
}

istream& operator >> (istream& str, CBinary& b)
{
char buf[b.len+2];
str >> buf;
CBinary t (buf);
b = t;
return str;
}
Прикрепленные файлы:
давно
Посетитель
276566
297
20.09.2011, 09:39
общий
20.09.2011, 12:01
Здравствуйте! скажите для данного примера нужно создавать файл.
Пример использования класса:
Код :

#include <conio.h>
#include <stdlib.h>
#include "Binary.h"
int _tmain(int argc, _TCHAR* argv[])
{ //пример
try {
CBinary a (2), b(12);
cin >> a;
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "a-b = " << (a-b) << endl;
cout << "a+b = " << (a+b) << endl;
cout << "a++ = " << (++a) << endl;
cout << "a-- = " << (--a) << endl;
cout << "~a = " << (~a) << endl;
} catch (char* ex) {
cout << ex;
}
getch(); //ожидаем пользователя
return 0;
}

Где диалоговая программа, которая позволяет вводить параметры, отлаживаемых методов?
Неизвестный
20.09.2011, 14:56
общий
Адресаты:
Уж диалоговую программу могли бы и сами составить. Ну, примерно так, наверно (см. приложенный файл).
Прикрепленные файлы:
fb25739c36d194204fd26f68391f2330.7z
давно
Посетитель
276566
297
24.09.2011, 16:35
общий
Здравствуйте! Можете прокомментировать весь файл Binary.cpp. Мой препод сказал что в одной из этих двух функций ошибка, он говорит что одна ф-ция должна возвращать старое значение числа, а другая новое.

CBinary& CBinary::operator++ ()
{
CBinary one (1);
*this+=one;
return *this;
}

CBinary& CBinary::operator-- ()
{
CBinary one (-1);
*this+=one;
return *this;
}
Неизвестный
04.10.2011, 16:05
общий
Адресаты:
Продублирую сюда для других, кто будет вопрос смотреть.
[code h=500]//Binary.cpp
#include "StdAfx.h"
#include "Binary.h"
#include <string.h>
#include <math.h>

CBinary::CBinary()
{
memset (number, 0, sizeof(char)*len); //заполняем память, выделенную под число, нулями
sign = 0; //знака нет
}

CBinary::CBinary (const CBinary &bin)
{
memcpy (number, bin.number, sizeof(char)*len); //копируем содержимое числа из bin в текущий объект
sign = bin.sign; //копируем знак
}

CBinary::CBinary (long data)
{
sign = 0; //знака нет
LongToBinary (data, number, sign); //преобразуем 10-е число к бинарному виду
}

CBinary::CBinary (const char* data)
{
sign = 0; //знака нет
char* dt = new char[strlen(data)+1]; //выделяем память под буфер
strcpy (dt, data); //копируем полученное строку
if (!CheckString (dt)) memset (number, 0, sizeof(char)*len); //если строка - некорректное бинарное число, то заполняем своё число 0
else BinaryFromString (dt, number, sign); //иначе преобразуем полученную строку к своему формату
}

bool IsNegative ()
{
return sign; //возвращаем знак
}

long CBinary::BinaryToLong ()
{
long res = number[1]; //записываем в результат первую цифру
for (int i=2; i<len; i++) //идём по числу
res = res*2 + number[i]; //набираем число путём умножения текущего числа на 2 и прибавления новой цифры
return res; //возвращаем результат
}

void CBinary::LongToBinary (long data, char* out, char &sgn)
{
int i = 1; //счётчик
sgn = (data<0); //определяем знак
data = abs(data); //убираем знак
memset (out, 0, sizeof(char)*len); //заполняем буфер нулями
while (data>1) { //пока число не кончится
out[len-i] = data%2; //Сохраняем остаток от деления на 2
data/=2; //делим на 2
i++; //переходим на следующую цифру
}
out[len-i] = data; //записываем последнюю цифру
}

void CBinary::BinaryFromString (char* in, char* out, char &sgn)
{
memset (out, 0, sizeof(char)*len); //заполняем буфер 0
int l = strlen (in); //сохраняем длину строки
for (int i=l-1, j=1; i>0; i--, j++) //идём по полученной строке с конца до второго символа
out[len-j] = in[i]-48; //заполняем буфер фактическими цифрами (из символа вычитаем код нуля)
if (in[0]=='-') sgn = 1; //проверяем знак на -
else if (in[0]=='+') sgn = 0; //на +
else { //знак отсутствует, первый символ - цифра
sgn = 0;
out[len-l] = in[0]-48;
}
}

bool CBinary::CheckString (char* data)
{
int l = strlen(data); //сохраняем длину
if (l>len-1) return false; //если длина превышает размер буфера возвращаем ошибку
int i = 0; //счётчик по строке

while (i<l && data[i]==' ') {data[i] = '0'; i++;} //заменяем пробелы нулями
if (i==l) return false; //если строка только из пробелов - ошибка

while (l>0 && data[l-1]==' ') l--; //удаляем пробелы в конце строки
if (l==0) return false; //если строка только из пробелов - ошибка
data[l] = '\0'; //Обозначаем новый конец строки

if (data[i]=='+' || data[i]=='-') { //если попался знак - помещаем его в начало строки
char t = data[i];
data[i] = data[0];
data[0] = t;
i++;
}

for (; i<l; i++) //остальные символы должны быть 0 или 1, иначе ошибка
if (data[i]!='1' && data[i]!='0') return false;

return true; //число корректно
}

void CBinary::ToExtraCode (char* extra, int count)
{
if (!sign) { //если знака нет, число равно дополнительному коду
memcpy (extra, number, sizeof(char)*len); //просто копируем число
return; //выход
}

memset (extra, 0, sizeof(char)*len); //заполняем буфер нулями

for (int i = len-1, j = 0; i>=0 && j<count; i--, j++) //инвертируем знаки числа до заданной длины
extra[i] = !number[i];
char one [len], res[len];
memset (one, 0, sizeof(char)*len); //создаём буфер - бинарная 1 (все 0, последний символ - 1)
one[len-1] = 1;
Summ (extra, one, res); //суммируем инвертированное число и 1 в буфер res
memcpy (extra, res, sizeof(char)*len); //копируем результат из буфера

extra[len-count-1] = 1; //дописываем знаковую 1
}

void CBinary::FromExtraCode (char* extra, int count)
{
memset (number, 0, sizeof(char)*len); //заполняем число 0

sign = extra[len-count-1]; //получаем знак
if (!sign) { //если знака нет, число равно дополнительному коду
for (int i=len-1, j=0; i>=0 && j<count; i--, j++) //просто копируем число
number[i] = extra[i];
return;//выход
}
for (int i=len-1, j=0; i>=0 && j<count; i--, j++) //инвертируем цифры до заданной длины
number[i] = !extra[i];
char one [len], res[len];
memset (one, 0, sizeof(char)*len); //создаём 1
one[len-1] = 1;
Summ (number, one, res); //прибавляем 1
memcpy (number, res, sizeof(char)*len); //копируем результат в наше число
}

void CBinary::Summ (char* slag1, char* slag2, char* res)
{
char one = 0, tmp; //знак переноса единицы, очередная сумма
memset (res, 0, sizeof(char)*len); //заполняем результат 0
for (int i=len-1; i>=0; i--) { //идём по числу с конца
tmp = slag1[i]+slag2[i]+one; //складываем цифры и перенесённую 1
if (tmp>1) { //если сумма >1
one = 1; //выставляем флаг переноса
res[i] = tmp%2; //ставим цифру - остаток от деления полученной суммы на 2
} else { //иначе
one = 0; //сбрасываем флаг
res[i] = tmp; //сохраняем цифру
}
}
if (one!=0) throw ("Very big summ!"); //если после выхода из цикла флаг не сброшен - сумма не влезла в буфер
}

CBinary& CBinary::operator= (CBinary b)
{
memcpy (number, b.number, sizeof(char)*len); //копируем число
sign = b.sign; //копируем знак
return *this; //возвращаем текущий объект
}

CBinary& CBinary::operator+= (CBinary b)
{
char ext1[len], ext2[len], res[len];
int c = max<int>(GetCount(), b.GetCount())+1; //определяем максимальное число значащих цифр и добавляем 1 для знака
if (c>=len) throw "Too big number"; //если вышло больше нашего буфера - ошибка
ToExtraCode (ext1, c); //преобразуем оба числа в дополнительный код
b.ToExtraCode (ext2, c);
int e1 = max<int>(GetCount(ext1), GetCount(ext2)); //это можно убрать, забыла удалить
Summ (ext1, ext2, res); //суммируем числа в дополнительном коде
FromExtraCode (res, c); //преобразуем к прямому коду
return *this; //возвращаем текущий объект
}

CBinary& CBinary::operator-= (CBinary b)
{
b.sign = !b.sign; //обращаем знак вычитаемого
*this+=b; //суммируем с уменьшаемым
return *this;//возвращаем текущий объект
}

CBinary& CBinary::operator++ ()
{
CBinary one (1); //создаём экземпляр класса = 1
*this+=one; //суммируем с текущим
return *this;//возвращаем текущий объект
}

CBinary& CBinary::operator-- ()
{
CBinary one (-1); //создаём экземпляр класса = -1
*this+=one;//суммируем с текущим
return *this;//возвращаем текущий объект
}

const char* CBinary::operator~ ()
{
char ext1[len]; //буфер под дополнительный код
ToExtraCode (ext1, GetCount()); //преобразуем с текущим числом знаков
ToString (user_extra, ext1); //преобразуем результат к строке
return user_extra; //возвращаем строку
}

void CBinary::ToString (char* str)
{
int i = 1, j = 0;
while (i<len && number[i]==0) i++; //пропускаем ведущие нули
if (sign) {str[j]='-'; j++;} //ставим знак
for (; i<len; i++, j++) str[j] = number[i]?'1':'0'; //пишем 0 или 1 в зависимости от исходной цифры
if (j==0) {str[j]='0'; j++;} //если число нулевое, пишем в результат ноль
str[j] = '\0'; //обозначаем конец строки
}

void CBinary::ToString (char* str, char* bin)
{//аналогично предыдущей функции, просто берёт цифры из параметра bin
int i = 0, j = 0;
while (i<len && bin[i]==0) i++;
for (; i<len; i++, j++) str[j] = bin[i]?'1':'0';
if (j==0) {str[j]='0'; j++;}
str[j] = '\0';
}

int CBinary::GetCount ()
{
int i = 0;
while (i<len && number[i]==0) i++; //пропускаем ведущие нули
return len-i; //возвращаем число знаков без них
}

int CBinary::GetCount (char* bin)
{//аналогично предыдущей функции, просто берёт цифры из параметра bin
int i = 0;
while (i<len && bin[i]==0) i++;
return len-i;
}


CBinary operator+ (CBinary &b1, CBinary &b2)
{
CBinary bin (b1); //копируем первое слагаемое
bin+=b2; //складываем со вторым
return bin; //возвращаем
}

CBinary operator- (CBinary &b1, CBinary &b2)
{
CBinary bin (b1); //копируем уменьшаемое
bin-=b2; //вычитаем из него вычитаемое
return bin; //возвращаем
}

ostream& operator << (ostream& str, CBinary& b)
{
char buf[b.len+2]; //выделяем буфер (максимальная длина числа плюс место под знак и под \0
b.ToString(buf); //преобразуем в строку
str << buf; //выводим в поток
return str; //возвращаем поток
}

istream& operator >> (istream& str, CBinary& b)
{
char buf[b.len+2];//выделяем буфер (максимальная длина числа плюс место под знак и под \0
str >> buf; //читаем его из потока
CBinary t (buf); //получаем из строки объект класса
b = t; //присваиваем в исходный объект
return str; //возвращаем поток
}[/code]
Форма ответа