Реализация собственной библиотеки my_decimal.h. Эта библиотека добавляет возможность работы с типом "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 число реализовано в виде четырехэлементного массива 32-разрядных целых чисел со знаком (int bits[4];
).
bits[0]
, bits[1]
, и bits[2]
содержат младшие, средние и старшие 32 бита 96-разрядного целого числа соответственно.
bits[3]
содержит коэффициент масштабирования и знак, и состоит из следующих частей:
- Биты от 0 до 15, младшее слово, не используются и равны нулю.
- Биты с 16 по 23 содержат показатель степени от 0 до 28, который указывает степень 10 для разделения целого числа.
- Биты с 24 по 30 не используются и равны нулю.
- Бит 31 содержит знак; 0 означает положительный, а 1 означает отрицательный.
Битовое представление различает отрицательные и положительные нули. Эти значения могут считаться эквивалентными во всех операциях.
Название оператора | Оператор | Функция |
---|---|---|
Сложение | + | int my_add(my_decimal value_1, my_decimal value_2, my_decimal *result) |
Вычитание | - | int my_sub(my_decimal value_1, my_decimal value_2, my_decimal *result) |
Умножение | * | int my_mul(my_decimal value_1, my_decimal value_2, my_decimal *result) |
Деление | / | int my_div(my_decimal value_1, my_decimal value_2, my_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 my_is_less(my_decimal, my_decimal) |
Меньше или равно | <= | int my_is_less_or_equal(my_decimal, my_decimal) |
Больше | > | int my_is_greater(my_decimal, my_decimal) |
Больше или равно | >= | int my_is_greater_or_equal(my_decimal, my_decimal) |
Равно | == | int my_is_equal(my_decimal, my_decimal) |
Не равно | != | int my_is_not_equal(my_decimal, my_decimal) |
Возвращаемое значение:
- 0 - FALSE
- 1 - TRUE
Преобразователь | Функция |
---|---|
Из int | int my_from_int_to_decimal(int src, my_decimal *dst) |
Из float | int my_from_float_to_decimal(float src, my_decimal *dst) |
В int | int my_from_decimal_to_int(my_decimal src, int *dst) |
В float | int my_from_decimal_to_float(my_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 преобразовываются все содержащиеся в нём значимые десятичные цифры. Если таких цифр больше 7, то значение числа округляется к ближайшему, у которого не больше 7 значимых цифр.
Уточнение про преобразование из числа типа decimal в тип int:
- Если в числе типа decimal есть дробная часть, то она отбросывается (например, 0.9 преобразуется 0)
Описание | Функция |
---|---|
Округляет указанное Decimal число до ближайшего целого числа в сторону отрицательной бесконечности. | int my_floor(my_decimal value, my_decimal *result) |
Округляет Decimal до ближайшего целого числа. | int my_round(my_decimal value, my_decimal *result) |
Возвращает целые цифры указанного Decimal числа; любые дробные цифры отбрасываются, включая конечные нули. | int my_truncate(my_decimal value, my_decimal *result) |
Возвращает результат умножения указанного Decimal на -1. | int my_negate(my_decimal value, my_decimal *result) |
Возвращаемое значение - код ошибки:
- 0 - OK
- 1 - ошибка вычисления
- Библиотека разработана на языке Си стандарта C11 с использованием компиятора gcc
- Код соответствует Google Style
- Решение оформлено как статическая библиотека (с заголовочным файлом my_decimal.h)
- Библиотека разработана в соответствии с принципами структурного программирования
- Подготовлено полное покрытие unit-тестами функций библиотеки c помощью библиотеки Check
- Предусмотрен Makefile для сборки библиотеки и тестов (с целями all, clean, test, my_decimal.a, gcov_report)
- В цели gcov_report формируется отчёт gcov в виде html страницы. Для этого unit-тесты запускаются с флагами gcov
- Не используется тип __int128
- Определяемый тип поддерживает числа от -79,228,162,514,264,337,593,543,950,335 до +79,228,162,514,264,337,593,543,950,335.