Листнинг программы.
//------------------------------------ i8_summator.cpp -------------------------------
// i8_summator.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace std;
// Основание системы счисления
#define BASE 8
//длина разрядной сетки целой части
#define MAX_DIGIT_GRID 16
// Максимальное число, которое может кодироваться в 8-ой системе
// с длиной разрядной сетки 16 (по формуле A(q.max)=(q^n)-1 )
#define MAX_NUM (pow(BASE,MAX_DIGIT_GRID)-1) // 07777777777777777
// Число знаков после запятой
#define MAX_FRACTION_PART 8
// @carry: флаг переноса в более старший разряд
// (т.е. число "в уме")
// @summ: результат сложения двух 8-ых чисел,
// величина которых не превышает 7
//
// P.S опытным путем установлено, что "в уме" может быть либо "1",
// либо "0", поэтому используется тип 'bool'
struct i8_data
{
bool carry ;
char summ ;
};
// @carry: флаг переноса
// @digits: массив цифр, который представляет собой восмеричное число
struct i8_data2
{
bool carry ;
deque<char> digits;
};
// i8_data - сложение двух восмеричных чисел
//
// P.S @a и @b должны быть меньше 8.
// В этой функции можно было бы использовать
// таблицу сложения, но поскольку в задании
// такое ограничение отсутствует, используется
// непосредственное вычисление суммы.
// Прим.: если a=5,b=7, то d.summ=4 ,d.carry=true;(07+05=014)
// если a=4,b=2, то d.summ=6 ,d.carry=false;(04+02=06)
i8_data add_c(char a,char b)
{
i8_data d;
if ( a + b > BASE - 1 )
{
d.summ = a + b - BASE ;
d.carry = true ;
}
else
{
d.summ = a + b ;
d.carry = false ;
}
return d;
}
// add_nc - сложение двух восмеричных чисел
// (аналогична add_c, но с небольшой разницей)
//
// P.S результат функции может быть больше 7
// Прим.: если a=7,b=7, то функция вернет 16 ;(07+07=16)
char add_nc(char a,char b)
{
i8_data d=add_c(a,b);
d.summ += d.carry * 10;
return d.summ;
}
// CalcSum - вычисление суммы двух положительных восмеричных чисел
// @first: первое восмеричное число
// @second: второе восмеричное число
// @carry: флаг, символизирующий необходимость добавления
// к указанным числам единицы
//
// P.S @first и @second должны иметь одинаковое количество элементов
i8_data2 CalcSum(const deque<char> &first,const deque<char> &second,bool carry=false)
{
bool carry_flag=carry;
i8_data2 d ;
// поразрядно вычисляем сумму
// Напр. first={3,6,4}, second={2,5,7}
// после цикла: d.digits={5,11,13}
for(int i=first.size()-1 ;i>= 0 ;i--)
{
d.digits.push_front(add_nc(first[i],second[i]));
}
for(int i=d.digits.size()-1; i>= 0 ;i--)
{
if(d.digits[i] < BASE)
{
if(!carry_flag) // если в "уме" 0
continue;
i8_data dt=add_c(d.digits[i],1);
d.digits[i]= dt.summ;
carry_flag = dt.carry;
continue;
}
// в этой ветке: 010 < d.digits[i] < 016
// Напр.: если d.digits[i]==014,и 1 в уме(carry=true), то
// d.digits[i]=5,и единица(из 015) в "уме"
d.digits[i]= d.digits[i] - 10 + carry_flag;
carry_flag = true;
}
d.carry = carry_flag;
return d;
}
// i10_to_i8_fraction - перевод дробной части 10-го числа
// в дробную часть 8-го
// @val: число меньшее 1
deque<char> i10_to_i8_fraction(double val)
{
deque<char> data;
int zero_count=0;
// нормализация ( т.е перед циклом напр.: val = 0.00045,
// после: val = 0.45,zero_count = 3
while ( true )
{
if (val * 10 > 1 || val == 0x00)
break;
val *= 10;
zero_count++;
}
for(int i=0;i<MAX_FRACTION_PART - zero_count ;i++)
{
double xxx = val * BASE ;
char x = static_cast<char>(xxx);
if (x == 0)
break;
data.push_back(static_cast<char>(xxx));
val = xxx - static_cast<__int64>(xxx);
}
if(zero_count > 0)
data.insert(data.begin(),zero_count ,0x00);
if(data.size() != BASE)
data.insert(data.end(),MAX_FRACTION_PART - data.size(),0x00);
return data;
}
// MK_print - вывод массива на стандартный поток вывода
// @val: массив символов
void MK_print(const deque<char> &val,const char *prefix = "")
{
cout << prefix;
if(val.size()==0)
cout << '0';
for(unsigned i=0;i<val.size();i++)
{
// элементы массива @val находятся в виде:
// 0x01,0x02,...,0x07 поэтому необходимо прибавить 0x30,
// чтобы на экран вывелись читабельные символы(т.к. напр. 0x36=='6')
cout << static_cast<char>(val[i] + 0x30);
}
}
// i10_to_i8 - преобразование 10-го числа в 8-е
// @val: целое число
//
// Возвращаемое значение - 8-е число в виде массива чисел
deque<char> i10_to_i8(__int64 val)
{
deque<char> d;
while(val >= BASE )
{
d.push_front(static_cast<char>(val % BASE) );
val /= BASE;
};
if (val < BASE && val > 0)
d.push_front(static_cast<char>(val % BASE) );
return d;
}
// i8_to_i10_and_print - перевод челой и дробной частей
// восмеричного числа в соотв. части
// десятичного и вывод результатов в консоль.
// @val: целая часть восмеричного числа.
// @fract_part: дробная часть восмеричного числа.
void i8_to_i10_and_print(const deque<char> &val,const deque<char> &fract_part)
{
__int64 result = 0;
for(int i=0,pos=val.size()-1;i<val.size();i++,pos--)
{
result += val[i] * pow(BASE,pos);
}
// переводим дробную часть 8-го числа в 10-ю
double d = 0;
for(int i=-1,pos=0;pos < fract_part.size();i--,pos++)
{
d += fract_part[pos] * pow(BASE,i);
}
cout << "The Sum is(oct+oct=oct->dec) : "<< result << '.';
// Вывод дробной части числа (выводятся 8 знаков после запятой)
for(int i=0;i<MAX_FRACTION_PART;i++)
{
d *=10;
cout << (int)d;
d-=static_cast<__int64>(d);
}
cout << endl;
}
// проверка корректности введенного числа
bool is_good_value(double d)
{
if(d > MAX_NUM || d < 0)
{
cout << "ERROR: number out of range..."<<endl;
return false;
}
return true;
}
int main(int argc, char* argv[])
{
double a,b;
cout << "Enter first number : ";
cin >> a;
if(!is_good_value(a))
return 1;
cout << "Enter second number : ";
cin >> b;
if(!is_good_value(b))
return 1;
// переводим целую часть введеных 10-ых чисел в соотв. 8-ые части.
deque<char> first = i10_to_i8(static_cast<__int64>(a));
deque<char> second = i10_to_i8(static_cast<__int64>(b));
// "a - static_cast<__int64>(a)" - таким образом получаем дробную часть числа
// далее переводим эту дробную 10-ю часть в 8-ую.
deque<char> first_frn = i10_to_i8_fraction(a - static_cast<__int64>(a));
deque<char> second_frn = i10_to_i8_fraction(b - static_cast<__int64>(b));
// если напр. first="1234567", second="52",
// то после этого блока second = "0000052"
// это необходимо для корректной работы функции CalcSum
if(first.size() > second.size())
second.insert(second.begin(),first.size()-second.size(),0x00);
else if (second.size()-first.size())
first.insert(first.begin(),second.size()-first.size(),0x00);
MK_print(first,"First number(octal) is : ");
cout << '.';
MK_print(first_frn);
cout <<endl;
MK_print(second,"Second number(octal) is : ");
cout << '.';
MK_print(second_frn);
cout <<endl;
// складываем дробные части
// если результат сложения >= 1, dd1.carry устанавливается в "true"
i8_data2 dd1 = CalcSum(first_frn,second_frn);
i8_data2 result = CalcSum(first,second,dd1.carry);
if (result.carry)
result.digits.push_front(0x01);
// Если произошло переполнение разрядной сетки
// выдаём соотв. сообщение.
if(result.digits.size() > MAX_DIGIT_GRID)
{
cout << "ERROR: overflow occured while adding two entered digits!!!"<<endl;
return 1;
}
MK_print(result.digits,"The Sum is(octal) : ");
cout << '.';
MK_print(dd1.digits);
cout <<endl;
// переводим полученное 8-е число в 10-е и выводим 10-е число на консоль.
i8_to_i10_and_print(result.digits,dd1.digits);
// выводим число,которое должно было бы получится
// при непосредственном сложении двух введенных чисел.
cout << "The Sum is(dec+dec=dec) : "<<a+b<<endl;
return 0;
}
//------------------------------ i8_summator.cpp ------------------------------
//------------------------------ stdafx.cpp ------------------------------------
#include "stdafx.h"
//------------------------------ stdafx.cpp ------------------------------------
//------------------------------ stdafx.h --------------------------------------
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <math.h>
#include <deque>
#include <iostream>
//------------------------------ stdafx.h --------------------------------------