Страница 1 из 2

Сложение, как на бумаге.

Добавлено: 16 ноя 2009, 11:34
Dragon
Задача следующая:
Написать программу, считывающую с клавиатуры два положительных целых числа длиной не более 20 знаков и выводящую их сумму. Эта программа считывает цифры как значения типа char. После прочтения всего числа символы заменятся значениями типа int. Цифры записываются в массив, и после их ввода с клавиатуры имеет смысл заменить порядок элементов этого массива обратным.
Программа должна выполнять сложение тем же способом, каким вы складываете числа на бумаге. Полученный результат необходимо записать в массив размером в 20 элементов, после чего вывести на экран. Если результат сложения будет содержать более 20 цифр, программа должна вывести сообщение о «переполнении разрядной сетки».
Сделал все, кроме вычисления суммы:

Код: Выделить всё

#include <iostream>
#include <cctype>
const int ARRAY_SIZE = 20;

struct digit
{
    int integer[ARRAY_SIZE];
    char letter[ARRAY_SIZE];
};

void fill_array(digit& a, int size, int& number_used);

int digit_to_int(char c);

void sort(int a[], int number_used);

//.......

void fill_array(digit& a, int size, int& number_used)
{
    int index = 0;
    char symbol;

    std::cout << "Enter up to 20 digits (to end line enter nondigit symbol):\n";
    std::cin >> symbol;
        while((isdigit(symbol)) && (index < ARRAY_SIZE))
    {
        a.letter[index] = symbol;
        index++;
        std::cin >> symbol;
    }
    number_used = index;

    for(index = 0; index < number_used; index++)
    {
        a.integer[index] = digit_to_int(a.letter[index]);
    }
}

int digit_to_int(char c)
{
    return(int(c) - int('0'));
}

void sort(int a[], int number_used)
{
    int start_ind = 0, end_ind = number_used-1, temp;
    while((start_ind < end_ind) && (start_ind != end_ind))
    {
        temp = a[start_ind];
        a[start_ind] = a[end_ind];
        a[end_ind] = temp;
        start_ind++;
        end_ind--;
    }
}
В чем у меня трудности и сомнения.
- Сложение массивов разной длины (скажем размеры [4] и [5]).
- Определение, когда прекратить считать (особенно, если массивы разной длины).
- Как я понимаю, то сумма будет выглядеть следующим образом: c[index] += (a[index] + b[index]). Тогда возвращаемся к п.1 и п.2.
- Как я понимаю, помимо итогового массива размером в 20 элементов, нужна переменная-счетчик, которая будет считать кол-во сложенных элементов. Если массив a и b содержат по 20 элементов, то счетчик будет равен 21 (и соответственно выдаст ошибку о переполнении), если сумма последних элементов будет > 9.
- Переменная-счетчик также нужна, чтобы обрезать массив, перед его выводом (выводить безе обратной сортировки - лишние действия ни к чему).
- Возможно есть смысл чтобы структура содержала сразу 2 числа, дабы упростить некоторые функции.

Пока вышло следующее (допустим что массивы a и b содержат значения 1234):

Код: Выделить всё

void sum(int a[], int a_size, int b[], int b_size)
{
    using namespace std;
    int c[20] = {0}, index, counter = 0;
    for(index = 0; index < a_size; index++)
    {
        c[index] += (a[index] + b[index]);
        counter++;
    }

    for(index = counter-1; index >=0; index--)
    {
        cout << c[index];
    }

    cout << endl;
}

Re: Сложение, как на бумаге.

Добавлено: 16 ноя 2009, 11:47
Хыиуду
A a_size и b_size заданы?
Далее, не заметил проверки на переполнение разряда. Т.е. если сумма двух чисел будет больше 9.

Re: Сложение, как на бумаге.

Добавлено: 16 ноя 2009, 11:54
Dragon
Хыиуду писал(а):A a_size и b_size заданы?
Далее, не заметил проверки на переполнение разряда. Т.е. если сумма двух чисел будет больше 9.
Тело программы выглядит так:

Код: Выделить всё

int main()
{
    using namespace std;

    int a_number_used, b_number_used;
    digit num1, num2;

    fill_array(num1, ARRAY_SIZE, a_number_used);
    fill_array(num2, ARRAY_SIZE, b_number_used);
    sort(num1.integer, a_number_used);
    sort(num2.integer, b_number_used);

    sum(num1.integer, a_number_used, num2.integer, b_number_used);

    return 0;
}
Переполнение разряда:

Код: Выделить всё

void sum(int a[], int a_size, int b[], int b_size)
{
    using namespace std;
    int c[ARRAY_SIZE] = {0}, index, counter = 0;
    for(index = 0; index < a_size; index++)
    {
        c[index] += (a[index] + b[index]);
        if(c[index] > 9)
        {
            c[index] = c[index] % 10; //Если сумма двух чисел больше 9.
            c[index+1] = 1;
        }
        counter++;
    }

    if(counter > ARRAY_SIZE)
    {
        cout << "ERORR.\n";
        exit(1);
    }
    else
    {
        for(index = counter-1; index >=0; index--)
        {
            cout << c[index];
        }
    }

    cout << endl;
}
Элементы массива складываются. Пока работает для двух чисел одинаковой длины. Если итоговое число будет на 1 разряд больше, то все равно выводится без него (думаю как исправить).
Пункты 1 и 2 актуальнее всего.

P.S>Логическая ошибка, из-за которой белиберда была, в том, что функции fill_array я передаю структуру, а не массив, следовательно надо передавать по ссылке :)

Re: Сложение, как на бумаге.

Добавлено: 16 ноя 2009, 14:50
DexterUa
Как сделать для разной длины?
Да просто - берешь изначально массивы интов заполненые нулями.
То есть когда ты запишешь свое число и перевернешь, то остаток массива это будет нули...

А дальше просто выбираешь не до a_size в
for(index = 0; index < a_size; index++)

а до максимального из a_size и b_size - таким образом пройдешь все значения.

Если разряд переполнится, то для этого хватит одного if

Код: Выделить всё

if(c[index] > 9)
        {
            c[index] = c[index] % 10; //Если сумма двух чисел больше 9.
            c[index+1] = 1;
            if(index==a_size-1)index++;
        }
но учти если поменяешь выше значение a_size, то и тут надо будет исправить

Re: Сложение, как на бумаге.

Добавлено: 16 ноя 2009, 21:23
Dragon
Не совсем ясно, как будет после переворота остаток нулями. Ведь если массив представляет из себя 1234000..., то перевернутым он будет ...0004321. Или вы имеете ввиду, чтобы после заполнения и переворота, если есть еще не занятые элементы, то заполнить их нулями?

Re: Сложение, как на бумаге.

Добавлено: 17 ноя 2009, 10:52
DexterUa
имеется ввиду что если число у вас например 1234567 а второе 1234
то запись в массив изначально будет 1234567000000 и 12340000000
то перевернув (я смотрел вы только цифри переворачиваете)
будет 76543210000000 и 43210000000000

тогда при сложении будет следущее:

7654321000
4321000000
-----------

и вы суммируете начиная с 0-го элемента (он тут слева)

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

Надеюсь понятно обьяснил =)

Re: Сложение, как на бумаге.

Добавлено: 17 ноя 2009, 11:06
Dragon
...запись в массив изначально будет 1234567000000 и 12340000000
то перевернув (я смотрел вы только цифри переворачиваете) будет...
будет 0000007654321 и 00000004321.

Или заполнять массивы с конца, тогда при перевороте будут нули после числа :)
=======

Как вариант (громоздкий), сначала к элементам массива с прибавить элементы массива a, а затем элементы массива b.
Тогда никакими нулями забивать массивы а и b не надо.

Пока код вышел сильно громоздким, думаю над оптимизацией:

Код: Выделить всё

void sum(int a[], int a_size, int b[], int b_size)
{
    using namespace std;
    int c[ARRAY_SIZE] = {0}, index, counter = 0;

    if(a_size >= b_size)
    {
        for(index = 0; index < b_size; index++)
        {
            c[index] += b[index];
        }

        for(index = 0; index < a_size; index++)
        {
            c[index] += a[index];
            if(c[index] > 9)
            {
                c[index] = c[index] % 10; //Если сумма двух чисел > 9
                c[index+1] += 1;
                if(index == (a_size - 1))
                {
                    counter++;
                }
            }
            counter++;
        }
    }
    else
    {
        for(index = 0; index < a_size; index++)
        {
            c[index] += a[index];
        }

        for(index = 0; index < b_size; index++)
        {
            c[index] += b[index];
            if(c[index] > 9)
            {
                c[index] = c[index] % 10; //Если сумма двух чисел > 9
                c[index+1] += 1;
                if(index == (b_size - 1))
                {
                    counter++;
                }
            }
            counter++;
        }
    }

    if(counter > ARRAY_SIZE)
    {
        cout << "ERORR.\n"; //"переполнение разрядной сетки"
        exit(1);
    }
    else
    {
        for(index = counter-1; index >= 0; index--)
        {
            cout << c[index];
        }
    }

    cout << endl;
}
P.S> Можно конечно сделать еще 1 функцию, которая будет осуществлять эти вычисления, а в качестве параметров будут передаваться больший и меньший массив (исходя из результата условия if). Но думается мне, что такой вариант будет не менее не оптимизирован (хотя хуже нынешнего наверное не найти).

Re: Сложение, как на бумаге.

Добавлено: 17 ноя 2009, 15:40
Albor
Dragon писал(а):будет 0000007654321 и 00000004321.

Тогда никакими нулями забивать массивы а и b не надо.
Не надо забивать ни какими нулями, ты ведь, считывая каждое число, считаешь количество символов. Складывай с концов исходных массивов, пока самый короткий не закончится.
ЗЫ. Не перестаю удивляться навязыванию нерационального способа решения. Как по мне здесь лучше использовать стек для исходных чисел - снимаем с вершин числа, складываем с учётом переноса, результат тоже в стек. Ни чего не нужно переворачивать и не нужно подсчитатывать количество символов, да и нет ограничения на максимальную длину входных данных.

Re: Сложение, как на бумаге.

Добавлено: 17 ноя 2009, 16:23
Dragon
Albor писал(а):Не надо забивать ни какими нулями, ты ведь, считывая каждое число, считаешь количество символов. Складывай с концов исходных массивов, пока самый короткий не закончится.
ЗЫ. Не перестаю удивляться навязыванию нерационального способа решения. Как по мне здесь лучше использовать стек для исходных чисел - снимаем с вершин числа, складываем с учётом переноса, результат тоже в стек. Ни чего не нужно переворачивать и не нужно подсчитатывать количество символов, да и нет ограничения на максимальную длину входных данных.
Увы, но до более рациональных решений у меня еще есть пробелы в теории (которые я заполняю по мере продвижения все дальше и дальше).

Re: Сложение, как на бумаге.

Добавлено: 17 ноя 2009, 17:29
Albor
пробелы в теории ты усугубляешь чрезмерным усложнением кода. Это я о дополнительных массивах. Входные данные можно читать в char-массивы. дублирующие int-массивы - это лишнее. Исходных данных достаточно для решения. Всё что нужно - это 3 char-массива. Ещё лучше использовать массив размером 21 символ (20 "полезных" элементов и 1 для завершающего нуля С-строки). По завершающему нулю всегда можно найти место начала подсчёта суммы. Если стек ты ещё не знаешь, то с-строки знать уже должен. Убирай сортировку, делай проще.