/
solidbase
/
C5_s21_decimal
Обзор
Документация
Войти
/
solidbase
/
C5_s21_decimal
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
src/tests/test_arithmetic.c
492 строки
15 KB
Dmitrii Isaev
earliema: test: add arithmetic edge cases
01 апр 2026, 15:01
01 апр 2026, 15:01
57c8273
Код
Авторство
О чём код?
#include <check.h> #include <limits.h> #include "../s21_decimal_arithmetic.h" #include "../s21_decimal_core.h" // Helper: make decimal from int mantissa, scale, sign static s21_decimal make_dec(int bits0, int bits1, int bits2, int scale, int sign) { s21_decimal d = {{bits0, bits1, bits2, 0}}; s21_set_scale(&d, scale); s21_set_sign(&d, sign); return d; } // Helper: convert decimal to double for approximate comparison static double dec_to_double(s21_decimal d) { double val = (double)(unsigned int)d.bits[0] + (double)(unsigned int)d.bits[1] * 4294967296.0 + (double)(unsigned int)d.bits[2] * 18446744073709551616.0; int scale = s21_get_scale(d); for (int i = 0; i < scale; i++) val /= 10.0; if (s21_get_sign(d)) val = -val; return val; } // ================================================================ // s21_add // ================================================================ START_TEST(test_add_simple_positive) { s21_decimal a = make_dec(3, 0, 0, 0, 0); s21_decimal b = make_dec(4, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 7); ck_assert_int_eq(s21_get_scale(r), 0); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_add_same_scale) { // 1.5 + 2.5 = 4.0 s21_decimal a = make_dec(15, 0, 0, 1, 0); s21_decimal b = make_dec(25, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 40); ck_assert_int_eq(s21_get_scale(r), 1); } END_TEST START_TEST(test_add_different_scales) { // 1.0 + 0.5 = 1.5 s21_decimal a = make_dec(10, 0, 0, 1, 0); s21_decimal b = make_dec(5, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 15); ck_assert_int_eq(s21_get_scale(r), 1); } END_TEST START_TEST(test_add_scale_mismatch) { // 1 (scale 0) + 0.1 (scale 1) = 1.1 (scale 1) s21_decimal a = make_dec(1, 0, 0, 0, 0); s21_decimal b = make_dec(1, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 11); ck_assert_int_eq(s21_get_scale(r), 1); } END_TEST START_TEST(test_add_positive_and_negative) { // 5 + (-3) = 2 s21_decimal a = make_dec(5, 0, 0, 0, 0); s21_decimal b = make_dec(3, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 2); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_add_negative_dominates) { // 3 + (-5) = -2 s21_decimal a = make_dec(3, 0, 0, 0, 0); s21_decimal b = make_dec(5, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 2); ck_assert_int_eq(s21_get_sign(r), 1); } END_TEST START_TEST(test_add_both_negative) { // -3 + (-4) = -7 s21_decimal a = make_dec(3, 0, 0, 0, 1); s21_decimal b = make_dec(4, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 7); ck_assert_int_eq(s21_get_sign(r), 1); } END_TEST START_TEST(test_add_zero_result) { // 5 + (-5) = 0 (sign must be positive) s21_decimal a = make_dec(5, 0, 0, 0, 0); s21_decimal b = make_dec(5, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(s21_is_zero(r), 1); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_add_zero_operand) { s21_decimal a = make_dec(42, 0, 0, 0, 0); s21_decimal zero = make_dec(0, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, zero, &r), 0); ck_assert_int_eq(r.bits[0], 42); } END_TEST START_TEST(test_add_overflow_positive) { // Max mantissa + 1 = overflow s21_decimal a = make_dec((int)0xFFFFFFFFu, (int)0xFFFFFFFFu, (int)0xFFFFFFFFu, 0, 0); s21_decimal b = make_dec(1, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 1); } END_TEST START_TEST(test_add_overflow_negative) { s21_decimal a = make_dec((int)0xFFFFFFFFu, (int)0xFFFFFFFFu, (int)0xFFFFFFFFu, 0, 1); s21_decimal b = make_dec(1, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 2); } END_TEST // ================================================================ // s21_sub // ================================================================ START_TEST(test_sub_simple) { // 10 - 3 = 7 s21_decimal a = make_dec(10, 0, 0, 0, 0); s21_decimal b = make_dec(3, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_sub(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 7); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_sub_negative_result) { // 3 - 10 = -7 s21_decimal a = make_dec(3, 0, 0, 0, 0); s21_decimal b = make_dec(10, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_sub(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 7); ck_assert_int_eq(s21_get_sign(r), 1); } END_TEST START_TEST(test_sub_with_scale) { // 1.5 - 0.5 = 1.0 s21_decimal a = make_dec(15, 0, 0, 1, 0); s21_decimal b = make_dec(5, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_sub(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 10); ck_assert_int_eq(s21_get_scale(r), 1); } END_TEST START_TEST(test_sub_negative_minus_negative) { // -3 - (-5) = 2 s21_decimal a = make_dec(3, 0, 0, 0, 1); s21_decimal b = make_dec(5, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_sub(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 2); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_sub_zero) { s21_decimal a = make_dec(7, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_sub(a, a, &r), 0); ck_assert_int_eq(s21_is_zero(r), 1); } END_TEST // ================================================================ // s21_mul // ================================================================ START_TEST(test_mul_simple) { // 6 * 7 = 42 s21_decimal a = make_dec(6, 0, 0, 0, 0); s21_decimal b = make_dec(7, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 42); } END_TEST START_TEST(test_mul_scales_add) { // 1.5 * 2.0 = 3.00 s21_decimal a = make_dec(15, 0, 0, 1, 0); s21_decimal b = make_dec(20, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 300); ck_assert_int_eq(s21_get_scale(r), 2); } END_TEST START_TEST(test_mul_sign_positive_negative) { // 5 * (-3) = -15 s21_decimal a = make_dec(5, 0, 0, 0, 0); s21_decimal b = make_dec(3, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 15); ck_assert_int_eq(s21_get_sign(r), 1); } END_TEST START_TEST(test_mul_sign_negative_negative) { // -4 * (-3) = 12 s21_decimal a = make_dec(4, 0, 0, 0, 1); s21_decimal b = make_dec(3, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 12); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_mul_by_zero) { s21_decimal a = make_dec(999, 0, 0, 0, 0); s21_decimal zero = make_dec(0, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, zero, &r), 0); ck_assert_int_eq(s21_is_zero(r), 1); } END_TEST START_TEST(test_mul_by_one) { s21_decimal a = make_dec(12345, 0, 0, 3, 0); s21_decimal one = make_dec(1, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, one, &r), 0); ck_assert_int_eq(r.bits[0], 12345); ck_assert_int_eq(s21_get_scale(r), 3); } END_TEST START_TEST(test_mul_cross_word) { // 0xFFFFFFFF * 2 = 0x1FFFFFFFE s21_decimal a = make_dec((int)0xFFFFFFFFu, 0, 0, 0, 0); s21_decimal b = make_dec(2, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 0); ck_assert_uint_eq((unsigned)r.bits[0], 0xFFFFFFFEu); ck_assert_int_eq(r.bits[1], 1); } END_TEST START_TEST(test_mul_overflow) { s21_decimal a = make_dec((int)0xFFFFFFFFu, (int)0xFFFFFFFFu, (int)0xFFFFFFFFu, 0, 0); s21_decimal b = make_dec(10, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_mul(a, b, &r), 1); } END_TEST // ================================================================ // s21_div // ================================================================ START_TEST(test_div_simple) { // 10 / 2 = 5.0 (stored as 5*10^k / 10^k due to precision scaling) s21_decimal a = make_dec(10, 0, 0, 0, 0); s21_decimal b = make_dec(2, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); ck_assert_int_eq(s21_get_sign(r), 0); ck_assert_double_eq_tol(dec_to_double(r), 5.0, 1e-10); } END_TEST START_TEST(test_div_by_zero) { s21_decimal a = make_dec(1, 0, 0, 0, 0); s21_decimal zero = make_dec(0, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, zero, &r), 3); } END_TEST START_TEST(test_div_produces_fraction) { // 1 / 2 = 0.5 s21_decimal a = make_dec(1, 0, 0, 0, 0); s21_decimal b = make_dec(2, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); // result should be non-zero with scale > 0 ck_assert_int_eq(s21_is_zero(r), 0); ck_assert_int_gt(s21_get_scale(r), 0); } END_TEST START_TEST(test_div_sign_positive_negative) { // 10 / (-2) = -5 s21_decimal a = make_dec(10, 0, 0, 0, 0); s21_decimal b = make_dec(2, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); ck_assert_int_eq(s21_get_sign(r), 1); } END_TEST START_TEST(test_div_sign_negative_negative) { // -9 / (-3) = 3 s21_decimal a = make_dec(9, 0, 0, 0, 1); s21_decimal b = make_dec(3, 0, 0, 0, 1); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); ck_assert_int_eq(s21_get_sign(r), 0); ck_assert_double_eq_tol(dec_to_double(r), 3.0, 1e-10); } END_TEST START_TEST(test_div_by_self) { // any / any = 1 (with scale) s21_decimal a = make_dec(12345, 0, 0, 2, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, a, &r), 0); ck_assert_int_eq(s21_is_zero(r), 0); ck_assert_int_eq(s21_get_sign(r), 0); } END_TEST START_TEST(test_div_zero_dividend) { s21_decimal zero = make_dec(0, 0, 0, 0, 0); s21_decimal b = make_dec(5, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_div(zero, b, &r), 0); ck_assert_int_eq(s21_is_zero(r), 1); } END_TEST START_TEST(test_div_with_scale) { // 1.0 / 4.0 = 0.25 s21_decimal a = make_dec(10, 0, 0, 1, 0); s21_decimal b = make_dec(40, 0, 0, 1, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); ck_assert_int_eq(s21_is_zero(r), 0); ck_assert_int_gt(s21_get_scale(r), 0); } END_TEST START_TEST(test_add_higher_scale_first) { // 1.5 + 2 = 3.5 s21_decimal a = make_dec(15, 0, 0, 1, 0); s21_decimal b = make_dec(2, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_add(a, b, &r), 0); ck_assert_int_eq(r.bits[0], 35); ck_assert_int_eq(s21_get_scale(r), 1); } END_TEST START_TEST(test_div_repeating_fraction) { // 2 / 3 = 0.6666...7 (rounds up at last digit) s21_decimal a = make_dec(2, 0, 0, 0, 0); s21_decimal b = make_dec(3, 0, 0, 0, 0); s21_decimal r; ck_assert_int_eq(s21_div(a, b, &r), 0); ck_assert_int_eq(s21_get_sign(r), 0); ck_assert_int_eq(s21_get_scale(r), 28); ck_assert_double_eq_tol(dec_to_double(r), 2.0 / 3.0, 1e-9); } END_TEST // ================================================================ // Add/Sub consistency: a - b = a + (-b) // ================================================================ START_TEST(test_sub_equals_add_negated) { s21_decimal a = make_dec(100, 0, 0, 1, 0); s21_decimal b = make_dec(37, 0, 0, 1, 0); s21_decimal neg_b = make_dec(37, 0, 0, 1, 1); s21_decimal r_sub, r_add; s21_sub(a, b, &r_sub); s21_add(a, neg_b, &r_add); ck_assert_int_eq(r_sub.bits[0], r_add.bits[0]); ck_assert_int_eq(r_sub.bits[1], r_add.bits[1]); ck_assert_int_eq(r_sub.bits[2], r_add.bits[2]); ck_assert_int_eq(s21_get_scale(r_sub), s21_get_scale(r_add)); ck_assert_int_eq(s21_get_sign(r_sub), s21_get_sign(r_add)); } END_TEST // ================================================================ // Mul/Div inverse: (a * b) / b ≈ a // ================================================================ START_TEST(test_mul_div_inverse) { s21_decimal a = make_dec(123, 0, 0, 2, 0); // 1.23 s21_decimal b = make_dec(4, 0, 0, 0, 0); // 4 s21_decimal product, quotient; ck_assert_int_eq(s21_mul(a, b, &product), 0); ck_assert_int_eq(s21_div(product, b, "ient), 0); // quotient should equal a (possibly with trailing zeros in scale) ck_assert_int_eq(s21_is_zero(quotient), 0); ck_assert_int_eq(s21_get_sign(quotient), 0); } END_TEST // ================================================================ // Suite // ================================================================ Suite* suite_arithmetic(void) { Suite* s = suite_create("arithmetic"); TCase* tc_add = tcase_create("add"); tcase_add_test(tc_add, test_add_simple_positive); tcase_add_test(tc_add, test_add_same_scale); tcase_add_test(tc_add, test_add_different_scales); tcase_add_test(tc_add, test_add_scale_mismatch); tcase_add_test(tc_add, test_add_positive_and_negative); tcase_add_test(tc_add, test_add_negative_dominates); tcase_add_test(tc_add, test_add_both_negative); tcase_add_test(tc_add, test_add_zero_result); tcase_add_test(tc_add, test_add_zero_operand); tcase_add_test(tc_add, test_add_overflow_positive); tcase_add_test(tc_add, test_add_overflow_negative); tcase_add_test(tc_add, test_add_higher_scale_first); suite_add_tcase(s, tc_add); TCase* tc_sub = tcase_create("sub"); tcase_add_test(tc_sub, test_sub_simple); tcase_add_test(tc_sub, test_sub_negative_result); tcase_add_test(tc_sub, test_sub_with_scale); tcase_add_test(tc_sub, test_sub_negative_minus_negative); tcase_add_test(tc_sub, test_sub_zero); suite_add_tcase(s, tc_sub); TCase* tc_mul = tcase_create("mul"); tcase_add_test(tc_mul, test_mul_simple); tcase_add_test(tc_mul, test_mul_scales_add); tcase_add_test(tc_mul, test_mul_sign_positive_negative); tcase_add_test(tc_mul, test_mul_sign_negative_negative); tcase_add_test(tc_mul, test_mul_by_zero); tcase_add_test(tc_mul, test_mul_by_one); tcase_add_test(tc_mul, test_mul_cross_word); tcase_add_test(tc_mul, test_mul_overflow); suite_add_tcase(s, tc_mul); TCase* tc_div = tcase_create("div"); tcase_add_test(tc_div, test_div_simple); tcase_add_test(tc_div, test_div_by_zero); tcase_add_test(tc_div, test_div_produces_fraction); tcase_add_test(tc_div, test_div_sign_positive_negative); tcase_add_test(tc_div, test_div_sign_negative_negative); tcase_add_test(tc_div, test_div_by_self); tcase_add_test(tc_div, test_div_zero_dividend); tcase_add_test(tc_div, test_div_with_scale); tcase_add_test(tc_div, test_div_repeating_fraction); suite_add_tcase(s, tc_div); TCase* tc_consistency = tcase_create("consistency"); tcase_add_test(tc_consistency, test_sub_equals_add_negated); tcase_add_test(tc_consistency, test_mul_div_inverse); suite_add_tcase(s, tc_consistency); return s; }