Программная реализация аппаратно-неразрешимых арифметических операций над длинными числами

0

 

 

 

Кафедра компьютерной безопасности и математического обеспечения информационных систем

 

 

КУРСОВАЯ РАБОТА

 

Программная реализация аппаратно-неразрешимых арифметических операций над длинными числами

 

 

Содержание

 

Введение. 3

1 Техническое задание. 4

2 Выбор методов, способов и средств реализации. 5

3 Описание основных алгоритмов. 6

4 Описание основных файлов программы.. 8

4.1 Файлы проекта и их основное назначение. 8

4.2 Описание основных модулей программ. 8

4.2.1 Модуль mainwindow.cpp главного окна. 8

4.2.2 Модуль longnumber.cpp арифметических операций арифметики произвольной точности. 10

5 Руководство пользователя. 11

5.1 Интерфейс и функциональность программы. 11

Список использованных источников. 15

Приложение А.. 16

 

Введение

 

Арифметические операции над числами реализуются с самого появления ЭВМ и программирования. Но у аппаратных средств всегда существовало одно существенное ограничение: длина машинного слова, то есть работать с числами, разрядность которых больше длины машинного слова, компьютер не может. К примеру, переменная типа int в языке программирования C++ может принимать значения от -2147483648 до 2147483647. Хотя это и довольно большие числа, но для некоторых вычислений их недостаточно. Выходом из данной ситуации является использование длинной арифметики.

Длинная арифметика — в вычислительной технике операции (сложение, вычитание, умножение, деление) над числами, разрядность которых превышает длину машинного слова данной вычислительной машины. Эти операции реализуются не аппаратно, а программно, используя базовые аппаратные средства работы с числами меньших порядков. Частный случай — арифметика произвольной точности — относится к арифметике, в которой длина чисел ограничена только объёмом доступной памяти.    

Основные потребители систем с использованием длинной арифметики:

  • Компьютеры низкой разрядности, микроконтроллеры. Например, микроконтроллеры серии AVR имеют 8-битный регистр и 10-битный АЦП — так что при обработке информации с АЦП без длинной арифметики не обойтись.
  • Криптография. Большинство систем шифрования данных, а также систем цифровой подписи данных используют целочисленную арифметику по модулю m, где m — очень большое положительное натуральное число, не обязательно простое. Для примера RSA, Криптосистема Рабина или Схема Эль‑Гамаля требуют наличие эффективных методов для операций перемножения и возведения в степень для чисел, имеющих порядки 10309.
  • Математическое и финансовое ПО, требующее, чтобы результат вычисления на компьютере совпал до последнего разряда с результатом вычисления на бумаге (Matlab, Maple, Mathematica). В частности, калькулятор Windows (начиная с Windows 95) проводит четыре арифметических действия с намного большей точностью, чем позволяет процессор x86. Для обычных научных и инженерных расчётов длинная арифметика применяется редко: ошибки во входных данных обычно намного больше, чем ошибки округления.

Во всем этом заключается актуальность данной работы.

Целью данной курсовой работы является создание калькулятора, реализующего операции арифметики произвольной точности над двумя числами.


 

1 Техническое задание

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

Исходное задание:

  • Должны быть реализованы поля для ввода двух вещественных чисел со знаком.
  • Должны быть реализованы кнопки для выбора арифметической операции и запуска вычислений.
  • Должны быть реализованы кнопки для полей, в которые вводятся числа, такие как копирование выделенной части числа из поля в буфер обмена, добавление в позицию курсора в поле содержимого буфера обмена, очистка поля, загрузка числа в поле из файла, сохранение числа из поля в файл.
  • Для поля результата должны быть реализованы кнопки копирования выделенной части числа из поля в буфер обмена, очистка поля, сохранение числа из поля в файл.
  • Должно быть реализовано закрытие окна калькулятора нажатием пункта Close в меню File в панели меню или при нажатии комбинации клавиш Ctrl+Shift+Escape или Ctrl+W.
  • Должен быть реализован запуск вычислений при нажатии комбинации клавиш Ctrl+F2.


2 Выбор методов, способов и средств реализации

В соответствии с исходным заданием было решено реализовать сохранение и загрузку чисел из текстового файла (файл с расширением .txt). Данный способ предоставляет возможность удобной записи числа напрямую в файл самим пользователем с последующей загрузкой этого числа в окно калькулятора.

Входные данные представляют собой вещественное число со знаком произвольной точности, в котором десятичным разделителем выступает точка, считываемое из QPlainTextEdit. Результат вычислений выводится также с помощью QPlainTextEdit. Выбор арифметической операции и запуск вычислений осуществляется с помощью кнопок с наглядными изображениями.

Программа реализует функции:

  • Четыре арифметические операции с двумя вещественными числами произвольной точности.
  • Проверки введенного значения на правильность.
  • Отображения полученного результата в отдельном поле.
  • Сохранения значения в текстовый файл.
  • Загрузки значения из текстового файла.
  • Работа с числовыми полями.

Для проектирования программ было решено пользоваться методами объектно-ориентированного программирования (ООП), как наиболее удобными для проектирования больших программных комплексов с возможностью расширения их в будущем, из-за большой гибкости в модификации и возможности оперирования со структурами данных, как с некоторыми абстрактными объектами. В качестве среды программирования была выбрана среда QT с языком программирования C++. Данная система программирования предоставляет большие возможности при проектировании интерфейсной части кроссплатформенных приложений, множество готовых, стандартных компонентов – элементов оконного приложения, большие удобства при кодировании и отладки программы, удобства при использовании ООП, содержит уникальную подсветку синтаксиса и систему автодополнения. Имеющийся инструмент разработки QT Designer позволяет организовывать графический пользовательский интерфейс в манере «что видишь, то и получишь». Также, стандартные библиотеки QT позволяют использовать динамические структуры данных, не заботясь об их реализации. Ко всему прочему, программы, реализованные на языке C++, отличаются повышенной скоростью и надёжностью. По перечисленным выше причинам она и была выбрана как средство реализации данной работы.


3 Описание основных алгоритмов

Для реализации данных алгоритмов длинное число представляется в памяти компьютера в виде линейного списка типа QList<int> разрядов целой части и разрядов дробной части, начиная с младших разрядов.

Далее введём следующие обозначения:

a – левый операнд, b – правый операнд, c – результат, k – перенос, i – итерация первого цикла, j – итерация второго цикла, t – текущее уменьшаемое, u – текущее вычитаемое, r – дополнительный порядок числа.

Для сложения и вычитания двух длинных чисел используется следующий алгоритм (для целой и дробной части алгоритм совпадает):

  • Если знаки a и b совпадают, то:
    • i = 0, k = 0;
    • Пока остались разряды в слагаемых:

начало

  • c[i] = a[i] + b[i] + k;
  • k = c[i] / 10;
  • c[i] -= k * 10;
  • i++;

конец

  • Если k не равен нулю, то:
    • c[i] = k;
  • Ставим знак числа
  • Иначе
    • a – большее число, b – меньшее;
    • i = 0, k = 0;
    • Пока остались разряды в уменьшаемом:

начало

  • c[i] = a[i] - b[i] - k;
  • Если c[i] < 0, то:
    • k = 1;
  • Иначе
    • k = 0;
  • c[i] += k * 10;
  • i++;

конец

  • Ставим знак числа

Для умножения двух длинных чисел используется следующий алгоритм:

  • i = 0;
  • a – конкатенация дробной и целой частей левого операнда, b - конкатенация дробной и целой частей правого операнда.
  • Пока остались разряды в правом множителе:

начало

  • j = 0, k = 0;
  • Пока остались разряды в левом множителе:

начало

  • c[i] = a[i] * b[j] + k;
  • k = c[i] / 10;
  • c[i] -= k * 10;
  • j++;

конец

  • i++;

конец

  • Если k не равен нулю, то:
    • c[i] = k;
  • Количество знаков после запятой в результате равен сумме количеств знаков после запятой у правого и левого множителя.
  • Если знаки у левого и правого множителя не равны, то ставим знак минус, иначе плюс.

Для деления двух длинных чисел используется следующий алгоритм:

  • Учёт переноса запятых.
  • Инвертирование a и
  • Пока не получен ответ или точность меньше 10000 знаков:

начало

  • Если в делимом остались цифры, то:
    • Берём одну цифру из делимого в t.
  • Иначе:
    • Берём ноль и к ответу добавляем ноль.
  • Если t < b, то
    • Добавить к ответу ноль и продолжить.
  • i = 1;
  • Пока i < 10:

начало

  • Если b * (i + 1) > t, то
    • Завершить

конец

  • К ответу добавляем i.
  • Элиминируем нули в начале t.

конец

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

 

 


4 Описание основных файлов программы

4.1 Файлы проекта и их основное назначение

Проект содержит несколько взаимосвязанных модулей. Первый из них «Mainwindow» предоставляет графический пользовательский интерфейс и передаёт введённые пользователем значения модулю «Longnumber». Модуль «Longnumber» осуществляет вычисления и возвращает полученные результаты обратно модулю «Mainwindow», который выводит значения на экран.

О составе проекта программы можно узнать из Таблицы 1:

 

Таблица 1 – Основные файлы проекта программы

Имя файла

Содержимое и назначение

CourseWork.pro

Файл проекта программы

main.cpp

Модуль главной формы проекта

mainwindow.cpp

Модуль, содержащий реализации функций графического интерфейса

mainwindow.h

Заголовочный файл модуля графического интерфейса

mainwindow.ui

Основной модуль формы программы

longnumber.h

Заголовочный файл модуля арифметических операций над длинными числами

longnumber.cpp

Модуль, содержащий реализации функций арифметических операций над длинными числами

 

 

4.2 Описание основных модулей программ

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

 

4.2.1 Модуль mainwindow.cpp главного окна

Данный модуль содержит класс MainWindow, основные поля которого отражены в таблице 2.

 

Таблица 2 – Основные поля класса MainWindow

Поля

Назначение

QPushButton pbCopyLeft

Кнопка, копирующая выделенную часть левого операнда в буфер обмена.

QPushButton pbCopyRight

Кнопка, копирующая выделенную часть левого операнда в буфер обмена.

QPushButton pbCopyResult

Кнопка, копирующая результат в буфер обмена.

QPushButton pbPasteLeft

Кнопка, вставляющая содержимое буфера обмена в левый операнд на позицию курсора.

QPushButton pbPasteRight

Кнопка, вставляющая содержимое буфера обмена в правый операнд на позицию курсора.

QPushButton pbClearLeft

Кнопка, очищающая поле левого операнда.

QPushButton pbClearRight

Кнопка, очищающая поле правого операнда.

QPushButton pbClearResult

Кнопка, очищающая поле результата.

QPushButton pbReadLeft

Кнопка, читающая значение из файла в поле левого операнда.

QPushButton pbReadRight

Кнопка, читающая значение из файла в поле правого операнда.

QPushButton pbWriteLeft

Кнопка, записывающая значение в файл из поля левого операнда.

QPushButton pbWriteRight

Кнопка, записывающая значение в файл из поля правого операнда.

QPushButton pbWriteResult

Кнопка, записывающая значение в файл из поля результата.

QPushButton pbAdd

Кнопка выбора операции сложения.

QPushButton pbSubtract

Кнопка выбора операции вычитания.

QPushButton pbMultiply

Кнопка выбора операции умножения.

QPushButton pbDivide

Кнопка выбора операции деления.

QPushButton pbCalculate

Кнопка запуска вычислений.

QPlainTextEdit pteLeft

Многострочное текстовое поле для ввода левого операнда с клавиатуры.

QPlainTextEdit pteRight

Многострочное текстовое поле для ввода правого операнда с клавиатуры.

QPlainTextEdit pteResult

Многострочное текстовое поле для вывода результата на экран.

 

В данном модуле реализуется графический пользовательский интерфейс программы. После нажатия пользователем на кнопку «Равно», передается сигнал, который обрабатывается соответствующим слотом. В случае корректного ввода исходных данных вызываются определенные методы вычислений. После чего на экран выводится результат вычислений в виде числового значения. В противном случае программа сообщит об ошибке.

4.2.2 Модуль longnumber.cpp арифметических операций арифметики произвольной точности

Данный модуль содержит класс LongNumber, основные поля которого отражены в таблице 3, а основные методы в таблице 4.

 

 

Таблица 3 – Основные поля класса LongNumber


Поля

Назначение

bool iss

Логическая переменная, хранящее знак длинного числа.

bool isf

Логическая переменная, хранящее информацию о наличии дробной части.

QList<int> w

Линейный список, хранящий целочисленные разряды длинного числа в виде целых чисел.

QList<int> f

Линейный список, хранящий дробные разряды длинного числа в виде целых чисел.

 

Таблица 4 – Основные методы класса LongNumber

Методы

Назначение

bool input(QString s);

   

Используется для ввода числа из текстового поля в память компьютера.

QString print();

 

Используется для вывода числа из памяти компьютера в текстовое поле.

void sum(LongNumber a, LongNumber b);

 

Служит для сложения или вычитания двух длинных чисел в зависимости от введённых данных.

void multiply(LongNumber a, LongNumber b);

 

Служит для умножения двух длинны чисел.

bool divide(LongNumber a, LongNumber b);

Служит для деления двух длинных чисел.

 

В данном модуле реализуются арифметические операции над длинными числами, а также их ввод и вывод. В случае возникновения ошибки объекты его вызвавшему возвращается значение false.


5 Руководство пользователя

5.1 Интерфейс и функциональность программы

 

При запуске программы на экране появляется окно «Calculator of long numbers», изображенное на рисунке 1.

 

Рисунок 1 – Главное окно программы

 

Главное окно программы содержит текстовые поля для ввода данных, кнопки для работы с ними, а также кнопки арифметических операций.

Если пользователь оставит поля пустыми и только выберет операцию, то при нажатии на кнопку «Равно» поля автоматически заполнятся нулями как на рисунке 2.

 

Рисунок 2 – Автоматическое заполнение нулями

 

 

Если же пользователь не выберет арифметическую операцию и нажмёт кнопку «Равно» программа сообщит об этом. Диалоговое окно данной ошибки изображено на рисунке 3.

 

Рисунок 3 – Сообщение об ошибке, в случае, когда пользователь не выбрал нужную арифметическую операцию

Если же операцией выбрано деление, а второе поле осталось пустым или заполнено нулями, то программа сообщит о делении на ноль как на рисунке 4.

Рисунок 4 – Сообщение об ошибке, в случае, когда пользователь делит на ноль

В случае, когда пользователь введёт неправильное число, к примеру с несколькими точками, символами вычитания или буквами, тогда программа выдаст сообщение об ошибке такое как на рисунке 5.

 

Рисунок 5 – Сообщение об ошибке, в случае, когда пользователь вводит неправильное число

В случае, когда все данные введены верно, пользователь получит результат с точностью до 10000 знаков после запятой, и результат можно прокручивать с помощью скроллбара с правой стороны как на рисунке 6.

Рисунок 6 – Результат ввода пользователем корректных данных.

 

Заключение

 

        Разработанная программа позволяет производить арифметические операции произвольной точности над двумя вещественными числами.

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

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

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

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


Список использованных источников

 

  • Павловская, Т.А. Программирование на языке высокого уровня. – СПб.: Питер, 2008. – 468 с.
  • Шлее, М. QT8. Профессиональное программирование на С++. – СПб.: БХВ-Петербург, 2010. – 896 с.
  • Материалы сайта http://ru.wikipedia.org.
  • Документация среды разработки QT.


Приложение А

(обязательное)

 

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

 

 

longnumber.h

 

#ifndef LONGNUMBER_H#define LONGNUMBER_H #include <QList> class LongNumber{    QList<int> w, f;    void clear();    void norm(LongNumber &a, LongNumber &b);    bool more(LongNumber a, LongNumber b);    bool more(QList<int> a, QList<int> b);    QList<int> mult(QList<int> a, int e);    QList<int> minus(QList<int> a, QList<int> b);    void inverse(QList<int> &a);    void inverse();    void unzero();public:    bool iss, isf;    LongNumber();    bool input(QString s);    QString print();    void sum(LongNumber a, LongNumber b);    void multiply(LongNumber a, LongNumber b);    bool divide(LongNumber a, LongNumber b);}; #endif // LONGNUMBER_H 

mainwindow.h

 

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

 

#include <QMainWindow>

 

namespace Ui {

class MainWindow;

}

 

class MainWindow : public QMainWindow

{

    Q_OBJECT

 

public:

    explicit MainWindow(QWidget *parent = 0);

    ~MainWindow();

 

private slots:

    void on_pbAdd_toggled(bool checked);

 

    void on_pbSubtract_toggled(bool checked);

 

    void on_pbMultiply_toggled(bool checked);

 

    void on_pbDivide_toggled(bool checked);

 

    void on_pbCalculate_clicked();

 

    void on_pbReadLeft_clicked();

 

    void on_pbReadRight_clicked();

 

    void on_pbWriteLeft_clicked();

 

    void on_pbWriteRight_clicked();

 

    void on_pbWriteResult_clicked();

 

    void on_pbCopyResult_clicked();

 

private:

    Ui::MainWindow *ui;

 

    int operation;

 

protected:

    void closeEvent(QCloseEvent *event);

 

    void keyPressEvent(QKeyEvent *event);

};

 

#endif // MAINWINDOW_H

 

longnumber.cpp

 

#include "longnumber.h"

#include <QList>

#include <QString>

 

 

LongNumber::LongNumber()

{

    iss = false, isf = false;

}

 

void LongNumber::clear()

{

    w.clear();

    f.clear();

    iss = false;

    isf = false;

}

 

void LongNumber::norm(LongNumber &a, LongNumber &b)//normalizing double reverse order number

{

    while(a.w.size() > b.w.size())

        b.w.append(0);

    while(a.w.size() < b.w.size())

        a.w.append(0);

    while(a.f.size() > b.f.size())

        b.f.prepend(0);

    while(a.f.size() < b.f.size())

        a.f.prepend(0);

}

 

bool LongNumber::more(LongNumber a, LongNumber b)//comparison double reverse order number

{

    for(int i = a.w.size() - 1; i >= 0; i--)

    {

        if(a.w[i] - b.w[i] > 0)

            return true;

        else if(a.w[i] - b.w[i] < 0)

            return false;

    }

    for(int i = a.f.size() - 1; i >= 0; i--)

    {

        if(a.f[i] - b.f[i] > 0)

            return true;

        else if(a.f[i] - b.f[i] < 0)

            return false;

    }

    return true;

}

 

void LongNumber::inverse(QList<int> &a)

{

    for(int i = 0; i < (a.size()/2); i++)

        qSwap(a[i], a[a.size() - i - 1]);

}

 

void LongNumber::inverse()

{

    inverse(w);

    inverse(f);

}

 

void LongNumber::unzero()//removing unnecessary zeroes

{

    while(w.size() > 1 && !w.last())

        w.removeLast();

    if(w.isEmpty())

        w.append(0);

    while(!f.isEmpty() && !f.first())

        f.removeFirst();

    if(!f.isEmpty())

        isf = true;

    else

        isf = false;

}

 

bool LongNumber::input(QString s)//inputing long number and conversion to reverse order

{

    clear();

    int i = 0;

    QString k;

    while(s[i] == 10 || s[i] == 32)//space and enter at begining

        i++;

    if(s[i] == 45)//is signded?

    {

        iss = true;

        i++;

    }

    while(i < s.size())

    {

        if(s[i] == 10 || s[i] == 32)//space and enter

        {

            i++;

            continue;

        }

        if(s[i] < 48 || s[i] > 57)//not digit?

        {

            if(s[i] == 46)//is fraction?

            {

                if(isf)

                    return false;

                else

                {

                    isf = true;

                    i++;

                    continue;

                }

            }

            else

                return false;

        }

        k = s[i];

        if(isf)//filling number

            f.append(k.toInt());

        else

            w.append(k.toInt());

        i++;

    }

    inverse();

    unzero();

    return true;

}

 

QString LongNumber::print()//conversion long fraction reverse order number to QString

{

    QString s = "";

    if(isf)//adding fraction

    {

        for(int i = 0; i < f.size(); i++)

            s.append(QString::number(f[i]));

        s.append(".");

    }

    for(int i = 0; i < w.size(); i++)//adding integer

        s.append(QString::number(w[i]));

    if(iss && !(s.size() == 1 && s[0] == 48))//adding sign

        s.append("-");

    QString k = "";

    for(int i = s.size() - 1; i >= 0; i--)//inversion

        k.push_back(s[i]);

    return k;

}

 

void LongNumber::sum(LongNumber a, LongNumber b)// add b to a considering sign

{

    int k = 0;

    clear();

    norm(a, b);

    if(a.iss == b.iss)//if signs is equal sum a and b in column

    {

        for(int i = 0; i < a.f.size(); i++)

        {

            f.append(a.f[i] + b.f[i] + k);

            k = f[i] / 10;

            f[i] -= 10 * k;

        }

        for(int i = 0; i < a.w.size(); i++)

        {

            w.append(a.w[i] + b.w[i] + k);

            k = w[i] / 10;

            w[i] -= 10 * k;

        }

        if(k)

            w.append(k);

        iss = a.iss;//and put sign of a

    }

    else

    {

        LongNumber c, d;

        if(more(a, b))//frob bigger subtract smaller in column

        {

            c = a;

            d = b;

        }

        else

        {

            c = b;

            d = a;

        }

        for(int i = 0; i < c.f.size(); i++)

        {

            f.append(c.f[i] - d.f[i] - k);

            if(f[i] < 0)

            {

                k = 1;

                f[i] += 10;

            }

            else

                k = 0;

        }

        for(int i = 0; i < c.w.size(); i++)

        {

            w.append(c.w[i] - d.w[i] - k);

            if(w[i] < 0)

            {

                k = 1;

                w[i] += 10;

            }

            else

                k = 0;

        }

        iss = c.iss;//and put sign of bigger

    }

    unzero();

}

 

void LongNumber::multiply(LongNumber a, LongNumber b)// multiply a by b

{

    int k = 0;

    clear();

    QList<int> x = a.f + a.w, y = b.f + b.w, z;//x - a converted to int, y - b converted to int, z - result

    if((!x.first() && x.size() == 1) || (!y.first() && y.size() == 1))//if a or b equal to zero, return zero

    {

        w.append(0);

        return;

    }

    for(int i = 0; i < y.size(); i++)//multiply in column

    {

        k = 0;

        for(int j = 0; j < x.size(); j++)

        {

            if(z.size() <= i + j)

                z.append(y[i] * x[j] + k);

            else

                z[i + j] += y[i] * x[j] + k;

            k = z[i + j] / 10;

            z[i + j] -= 10 * k;

 

        }

        if(k)

            z.append(k);

    }

    f = z.mid(0, a.f.size() + b.f.size());//conversion to fraction

    w = z.mid(a.f.size() + b.f.size());

    if(a.iss != b.iss)//if signs is not equal put minus

        iss = true;

    unzero();

}

 

bool LongNumber::more(QList<int> a, QList<int> b)//comparison of preorder int numbers

{

    if(a.size() > b.size())

        return true;

    else if(a.size() < b.size())

        return false;

    else

        for(int i = 0; i < a.size(); i++)

        {

            if(a[i] - b[i] > 0)

                return true;

            else if(a[i] - b[i] < 0)

                return false;

        }

    return false;

}

 

QList<int> LongNumber::mult(QList<int> a, int e)//calculate subtrahend

{

    int k = 0;//transfer number

    QList<int> c;

    for(int i = a.size() - 1; i >= 0; i--)//multiply a by e in preorder

    {

        c.prepend(e * a[i] + k);

        k = c[0] / 10;

        c[0] -= 10 * k;

    }

    if(k)

        c.prepend(k);

    return c;

}

 

QList<int> LongNumber::minus(QList<int> a, QList<int> b)//calculate remainder

{

    int k = 0;//transfer number

    QList<int> c;//result

    if(a.size() > b.size())//normalization

        b.prepend(0);

    for(int i = a.size() - 1; i >= 0; i--)//subtract b from a

    {

        c.prepend(a[i] - b[i] - k);

        if(c.first() < 0)

        {

            k = 1;

            c.first() += 10;

        }

        else

            k = 0;

    }

    while(c.size() > 1)//removing zeroes from begining

    {

        if(c[0] == 0)

            c.removeFirst();

        else

            break;

    }

    return c;

}

 

bool LongNumber::divide(LongNumber a, LongNumber b)// a/b

{

    clear();//clear result

    int k = 0, r = 0;//k - position of point, r - additional number exponent

    QList<int> x, y, z, t, u;//x - left expression, y - right expression, z - result, t - current number for calculations, u - subtrahend

    r = b.f.size() - a.f.size();//counting size of double to int conversation

    x = a.f + a.w;//conver to int

    y = b.f + b.w;

    while(!x.isEmpty())//remowing side zeroes

    {

        if(x[0] == 0)

        {

            r++;

            x.removeFirst();

        }

        else if(x.last() == 0)

            x.removeLast();

        else

            break;

    }

    while(!y.isEmpty())

    {

        if(y[0] == 0)

        {

            r--;

            y.removeFirst();

        }

        else if(y.last() == 0)

            y.removeLast();

        else

            break;

    }

    if(y.isEmpty())//division by zero

    {

        w.append(0);

        return false;

    }

    if(x.isEmpty())//divison zero by number

    {

        w.append(0);

        return true;

    }

    inverse(x);

    inverse(y);

    while((!x.isEmpty() || !t.isEmpty()) && (!isf || z.size() + k < 10000))//subtract until end or accuracy is 10000 signs after point

    {

        if(!x.isEmpty())//if left epression has digits

        {

            t.append(x[0]);//take digit

            x.removeFirst();

        }

        else

        {

            t.append(0);//add zero

            if(!isf)//if is not fraction

            {

                isf = true;

                k = z.size();

            }

        }

        if(t.size() < y.size() || more(y, t))

        {

            z.append(0);

                                                             continue;

        }

        int i = 1;

        for(; i < 10; i++)//search for digit for answer

        {

            u = mult(y, i + 1);

            if(more(u, t))//if next number more than t digit is found

                break;

        }

        z.append(i);//adding found digit

        u = mult(y, i);

        t = minus(t, u);//calculation of remainder

        while(!t.isEmpty())//remove zeroes from current number

        {

            if(t[0] == 0)

                t.removeFirst();

            else

                break;

        }

    }

    if(isf)//if is fraction

        k += r;//change position of point

    else

        k = z.size() + r;//adding numer exponent

    if(k >= z.size())//if point further than end of result adding zeroes to end and answer is int

    {

        k -= z.size();

        for(int i = 0; i < k; i++)

            z.append(0);

        isf = false;

        w = z;

    }

    else if(k < 0)//if point earlier than begining of number adding zeroes to begin and answer is fraction

    {

        for(int i = k; i < 0; i++)

            z.prepend(0);

        isf = true;

        k = 0;

        w.append(0);

        f = z;

    }

    else//writing of answer

    {

        w = z.mid(0, k);

        f = z.mid(k);

    }

    inverse();

    if(a.iss != b.iss)//sign calculation

        iss = true;

    unzero();

    return true;

}

 

main.cpp

 

#include "mainwindow.h"#include <QApplication> int main(int argc, char *argv[]){    QApplication a(argc, argv);    MainWindow w;    w.show();     return a.exec();}

 

mainwindow.cpp

 

Скачать: otchet.doc

 

Категория: Курсовые / Компьютерные технологии курсовые

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.