Skip to content

IKYTARO/Decimal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Decimal

image

Реализация собственной библиотеки decimal.h.

Оглавление

Аннотация

В данном проекте представлена реализация библиотеки decimal.h на языке программирования С. Хотя тип «decimal» отсутствует в стандарте языка он, тем не менее, критически важен, например, для финансовых расчетов, где недопустимы погрешности вычислений, свойственные типам с плавающей точкой. Данный проект позволяет познакомится с задачами обработки финансовой информации, погрузится в вопросы внутреннего представления различных типов данных и закрепить структурный подход.

Тип Decimal

Тип Decimal представляет десятичные числа в диапазоне от положительных 79,228,162,514,264,337,593,543,950,335 до отрицательных 79,228,162,514,264,337,593,543,950,335. Значение Decimal по умолчанию равно 0. Decimal подходит для финансовых расчетов, которые требуют большого количества значимых целых и дробных цифр и отсутствия ошибок округления. Этот тип не устраняет необходимость округления. Скорее, сводит к минимуму количество ошибок из-за округления.

Когда результат деления и умножения передается методу округления, результат не страдает от потери точности.

Decimal число - это значение с плавающей точкой, состоящее из знака, числового значения, где каждая цифра находится в диапазоне от 0 до 9, и коэффициента масштабирования, который указывает положение десятичной точки, разделяющей целые и дробные части числового значения.

Двоичное представление Decimal состоит из 1-разрядного знака, 96-разрядного целого числа и коэффициента масштабирования, используемого для деления 96-разрядного целого числа и указания того, какая его часть является десятичной дробью. Коэффициент масштабирования неявно равен числу 10, возведенному в степень в диапазоне от 0 до 28. Следовательно, двоичное представление Decimal имеет вид ((от -2^96 до 2^96) / 10^(от 0 до 28)), где -(2^96-1) равно минимальному значению, а 2^96-1 равно максимальному значению.

Коэффициент масштабирования также может сохранять любые конечные нули в Decimal. Эти конечные нули не влияют на значение в арифметических операциях или операциях сравнения.

Двоичное представление

Двоичное представление Decimal состоит из 1-разрядного знака, 96-разрядного целого числа и коэффициента масштабирования, используемого для деления целого числа и указания того, какая его часть является десятичной дробью. Коэффициент масштабирования неявно равен числу 10, возведенному в степень в диапазоне от 0 до 28.

Decimal реализован в виде четырех 32-разрядных целых чисел без знака(int bits[4];):

typedef struct {
    uint32_t lo32;
    uint32_t mi32;
    uint32_t hi32;
    uint32_t flags;
} decimal;

lo32, mi32, и hi32 содержат младшие, средние и старшие 32 бита 96-разрядного целого числа соответственно.

flags содержит коэффициент масштабирования и знак, и состоит из следующих частей:

  • Биты от 0 до 15, младшее слово, не используются и должны быть равны нулю.
  • Биты с 16 по 23 должны содержать показатель степени от 0 до 28, который указывает степень 10 для разделения целого числа.
  • Биты с 24 по 30 не используются и должны быть равны нулю.
  • Бит 31 содержит знак; 0 означает положительный, а 1 означает отрицательный.

Битовое представление различает отрицательные и положительные нули. Эти значения считаются эквивалентными во всех операциях.

Реализованные функции

Арифметические операторы

Название оператора Оператор Функция
Сложение + int add(decimal value_1, decimal value_2, decimal *result)
Вычитание - int sub(decimal value_1, decimal value_2, decimal *result)
Умножение * int mul(decimal value_1, decimal value_2, decimal *result)
Деление / int div(decimal value_1, decimal value_2, decimal *result)
Остаток от деления Mod int mod(decimal value_1, decimal value_2, decimal *result)

Функции возвращают код ошибки:

  • 0 - OK
  • 1 - число слишком велико или равно бесконечности
  • 2 - число слишком мало или равно отрицательной бесконечности
  • 3 - деление на 0

Уточнение про числа, не вмещающиеся в мантиссу:

  • При получении чисел, не вмещающихся в мантиссу при арифметических операциях, использовать банковское округление (например, 79,228,162,514,264,337,593,543,950,335 - 0.6 = 79,228,162,514,264,337,593,543,950,334)

Операторы сравнение

Название оператора Оператор Функция
Меньше < int is_less(decimal, decimal)
Меньше или равно <= int is_less_or_equal(decimal, decimal)
Больше > int is_greater(decimal, decimal)
Больше или равно >= int is_greater_or_equal(decimal, decimal)
Равно == int is_equal(decimal, decimal)
Не равно != int is_not_equal(decimal, decimal)

Возвращаемое значение:

  • 0 - FALSE
  • 1 - TRUE

Преобразователи

Преобразователь Функция
Из int int from_int_to_decimal(int src, decimal *dst)
Из float int from_float_to_decimal(float src, decimal *dst)
В int int from_decimal_to_int(decimal src, int *dst)
В float int from_decimal_to_float(decimal src, float *dst)

Возвращаемое значение - код ошибки:

  • 0 - OK
  • 1 - ошибка конвертации

Уточнение про преобразование числа типа float:

  • Если числа слишком малы (0 < |x| < 1e-28), вернуть ошибку и значение, равное 0
  • Если числа слишком велики (|x| > 79,228,162,514,264,337,593,543,950,335) или равны бесконечности, вернуть ошибку
  • При обработке числа с типом float преобразовывать все содержащиеся в нём цифры

Уточнение про преобразование из числа типа decimal в тип int:

  • Если в числе типа decimal есть дробная часть, то её следует отбросить (например, 0.9 преобразуется 0)

Математические функции

Описание Функция
Округляет указанное Decimal число до ближайшего целого числа в сторону отрицательной бесконечности. int floor(decimal value, decimal *result)
Округляет указанное Decimal число до ближайшего целого числа в сторону положительной бесконечности. int ceil(decimal value, decimal *result)
Округляет Decimal до ближайшего целого числа согласно режиму округления. int round(decimal value, decimal *result)
Возвращает целые цифры указанного Decimal числа; любые дробные цифры отбрасываются, включая конечные нули. int truncate(decimal value, decimal *result)
Возвращает результат умножения указанного Decimal на -1. int negate(decimal value, decimal *result)

Возвращаемое значение - код ошибки:

  • 0 - OK
  • 1 - ошибка вычисления

Управление округлением

В текущей версии библиотеки поддреживается 4 типа округления, которые определены в перечислении:

typedef enum { 
    BANK  = 0, // банковское округление
    FLOOR = 1, // округление вниз
    CEIL  = 2, // округление вверх
    MATH  = 3  // математическое округление (по умолчанию)
} decimal_rounding_t;

Управление и контроль типо округления, реализованного в функции round, осуществляется с помощью функций:

Описание Функция
Устанавливает тип округления согласно decimal_rounding_t. В случае успеха возвращает true, иначе - false. bool decimal_set_round(int mode)
Возвращает текущий тип округления. int decimal_get_round(void)

Структура проекта

Проект имеет модульную структуру для лучшей организации кода.

└── Decimal/            # Репозиторий с исходным кодом и ресурсами 
    ├── misc/           # Файлы, используемые в документации
    ├── tests/          # Директория с модульными тестами  
    ├── src/            # Директория с реализацией библиотеки
    │   ├── arithmetic/     # Директория с модулем арифметических операций 
    │   ├── comparison/     # Директория с модулем операций сравнения
    │   ├── conversion/     # Директория с модулем операций преобразования
    │   ├── math/           # Директория с модулем математических операций  
    │   ├── private/        # Директория с модулем приватных вспомогательных функций
    │   └── types.h         # Хаголовочный файл с общими типами
    ├── decimal.h       # Главный заголовочный файл библиотеки
    ├── Makefile        # Управление сборкой
    └── README.md       # Документация на русском

Установка и сборка

Для сборки проекта требуется make и компилятор gcc.

  1.  Клонируйте репозиторий:
git clone [ссылка на РЕПОЗИТОРИЙ]

Цели Makefile

Основные цели сборки

  • Данный проект собирается в виде статической библиотеки my_string.a. Модуль тестирования собирается и запускается командами make all или make test. Отчет о тестировании заносится в файл test_report.log, который генерируется автоматически при запуске указанных команд.
  • Для запуска тестирования необходимо установить библиотеку Check, например для Ubuntu:
sudo apt install check
  • Для формирования отчета о тестировании необходимо установить gcov, например для Ubuntu:
sudo apt install gcov
Команда       Описание
make all     Сборка библиотеки и запуск тестов
make library Сборка статической библиотеки my_string.a
make test     Сборка библиотеки и запуск тестов
make gcov_report Сборка библиотеки и запуск тестов с выпуском отчета о тестировании
make view-report Выполнение цели gcov_report и открытие отчета о тестировании
make clean Очистка сборки

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

Для форматирования кода потребуется clang-format, исходные настройки стиля (.clang-format) прилагаются к проекту. Для статического анализа кода потребуется cppcheck (2.7).

Команда             Описание    
make format       Форматирование кода clang-format
make check-format Проверка стиля кода          
make cppcheck     Статический анализатор кода    

Проверка программы

Для проверки утечек памяти потребуется valgrind (3.18.1).

Команда             Описание              
make valgrind     Анализ программы на наличие утечек памяти                                      

About

Реализация библиотеки decimal.h.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors