Skip to content

Commit

Permalink
[ISSUE-0041]: bigint_div implementation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
SzigetiJ committed Dec 7, 2023
1 parent 77aa696 commit ec5d47e
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 40 deletions.
31 changes: 30 additions & 1 deletion src/biguint128.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,35 @@ BigUIntPair128 biguint128_div(const BigUInt128 *a, const BigUInt128 *b) {
return retv;
}

BigUIntPair128 bigint128_div(const BigUInt128 *a, const BigUInt128 *b) {
// work with copies
BigUInt128 ab[] = {biguint128_ctor_copy(a), biguint128_ctor_copy(b)};
// check signs
buint_bool neg[] = {is_bigint_negative_(a), is_bigint_negative_(b)};
// convert
for (unsigned int i = 0U; i<2; ++i) {
if (neg[i]) {
biguint128_dec(&ab[i]);
biguint128_not_assign(&ab[i]);
}
}

// calling the wrapped function
BigUIntPair128 retv = biguint128_div(&ab[0], &ab[1]);

// afterwork
if (!neg[0] != !neg[1]) {
biguint128_dec(&retv.first);
biguint128_not_assign(&retv.first);
}
if (neg[0]) {
biguint128_dec(&retv.second);
biguint128_not_assign(&retv.second);
}
return retv;
}


buint_bool biguint128_lt(const BigUInt128 *a, const BigUInt128 *b) {
FOREACHCELL(i) {
buint_size_t j = BIGUINT128_CELLS - i - 1;
Expand All @@ -609,7 +638,7 @@ buint_bool biguint128_lt(const BigUInt128 *a, const BigUInt128 *b) {
buint_bool bigint128_lt(const BigUInt128 *a, const BigUInt128 *b) {
buint_bool neg_a = is_bigint_negative_(a);
buint_bool neg_b = is_bigint_negative_(b);
return (neg_a == neg_b) ?
return (!!neg_a == !!neg_b) ?
biguint128_lt(a,b): // compare them in the usual way
neg_a; // if only one of them is negative, a must be negative to be lower than b.
}
Expand Down
6 changes: 6 additions & 0 deletions src/biguint128.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ BigUIntPair128 biguint128_dmul(const BigUInt128 *a, const BigUInt128 *b);
*/
BigUIntPair128 biguint128_div(const BigUInt128 *a, const BigUInt128 *b);

/**
@brief Division of signed values.
@return First: quotient, second: remainder so that (a == b * quotient + remainder) is true.
*/
BigUIntPair128 bigint128_div(const BigUInt128 *a, const BigUInt128 *b);

// comparison
/**
@brief 'Less than' relation.
Expand Down
77 changes: 41 additions & 36 deletions tests/biguint128_eq_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ typedef enum {
typedef struct {
CStr left;
CStr right;
BigUIntSortRelation rel;
BigUIntSortRelation rel_pp;
BigUIntSortRelation rel_np;
BigUIntSortRelation rel_pn;
BigUIntSortRelation rel_nn;
} BigUIntSortRelTestVector;

const BigUIntSortRelTestVector samples[]={
{STR("0"),STR("0"),BIGUINT_EQ},
{STR("0"),STR("1"),BIGUINT_LT},
{STR("FFFFFFFF"),STR("FFFFFFFF"),BIGUINT_EQ},
{STR("FFFFFFFF"),STR("100000000"),BIGUINT_LT},
{STR("0"),STR("100000000"),BIGUINT_LT},
{STR("0"),STR("10000000000000000"),BIGUINT_LT},
{STR("0"),STR("100000000000000000000000000000000"),BIGUINT_LT},
{STR("0"),STR("10000000000000000000000000000000000000000000000000000000000000000"),BIGUINT_LT},
{STR("1"),STR("100000001"),BIGUINT_LT},
{STR("100000001"),STR("100000001"),BIGUINT_EQ},
{STR("FFFFFFFFF00000000"),STR("FFFFFFFF00000000FFFFFFFF"),BIGUINT_LT},
{STR("A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A"),BIGUINT_GT},
{STR("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A"),BIGUINT_GT},
{STR("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A"),BIGUINT_GT},
{STR("0"),STR("0"),BIGUINT_EQ,BIGUINT_EQ,BIGUINT_EQ,BIGUINT_EQ},
{STR("0"),STR("1"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("FFFFFFFF"),STR("FFFFFFFF"),BIGUINT_EQ,BIGUINT_LT,BIGUINT_GT,BIGUINT_EQ},
{STR("FFFFFFFF"),STR("100000000"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("0"),STR("100000000"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("0"),STR("10000000000000000"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("0"),STR("100000000000000000000000000000000"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("0"),STR("10000000000000000000000000000000000000000000000000000000000000000"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("1"),STR("100000001"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("100000001"),STR("100000001"),BIGUINT_EQ,BIGUINT_LT,BIGUINT_GT,BIGUINT_EQ},
{STR("FFFFFFFFF00000000"),STR("FFFFFFFF00000000FFFFFFFF"),BIGUINT_LT,BIGUINT_LT,BIGUINT_GT,BIGUINT_GT},
{STR("A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A"),BIGUINT_GT,BIGUINT_LT,BIGUINT_GT,BIGUINT_LT},
{STR("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A"),BIGUINT_GT,BIGUINT_LT,BIGUINT_GT,BIGUINT_LT},
{STR("A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5"),STR("5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A"),BIGUINT_GT,BIGUINT_LT,BIGUINT_GT,BIGUINT_LT},
};
int sample_len = sizeof(samples) / sizeof(BigUIntSortRelTestVector);

Expand Down Expand Up @@ -59,20 +62,20 @@ int test_sortrel0() {
buint_bool result_eq_rev = biguint128_eq(&b, &a);

// process result
if (!!result_lt != (samples[i].rel==BIGUINT_LT)) {
fprintf(stderr, "[%s < %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel==BIGUINT_LT), bool_to_str(result_lt));
if (!!result_lt != (samples[i].rel_pp==BIGUINT_LT)) {
fprintf(stderr, "[%s < %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel_pp==BIGUINT_LT), bool_to_str(result_lt));
fail = 1;
}
if (!!result_eq != (samples[i].rel==BIGUINT_EQ)) {
fprintf(stderr, "[%s == %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel==BIGUINT_EQ), bool_to_str(result_eq));
if (!!result_eq != (samples[i].rel_pp==BIGUINT_EQ)) {
fprintf(stderr, "[%s == %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel_pp==BIGUINT_EQ), bool_to_str(result_eq));
fail = 1;
}
if (!!result_lt_rev != (samples[i].rel==BIGUINT_GT)) {
fprintf(stderr, "[%s < %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel==BIGUINT_GT), bool_to_str(result_lt));
if (!!result_lt_rev != (samples[i].rel_pp==BIGUINT_GT)) {
fprintf(stderr, "[%s < %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel_pp==BIGUINT_GT), bool_to_str(result_lt));
fail = 1;
}
if (!!result_eq_rev != (samples[i].rel==BIGUINT_EQ)) {
fprintf(stderr, "[%s == %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel==BIGUINT_EQ), bool_to_str(result_eq));
if (!!result_eq_rev != (samples[i].rel_pp==BIGUINT_EQ)) {
fprintf(stderr, "[%s == %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel_pp==BIGUINT_EQ), bool_to_str(result_eq));
fail = 1;
}
++run_cnt;
Expand Down Expand Up @@ -112,31 +115,33 @@ int test_sortrel1() {
buint_bool result_gt_3 = bigint128_lt(&b_neg, &a_neg);

// process result
if (!result_lt_1 && !(za && zb)) { // a not positive value is less than a not negative value, unless they both are 0
fprintf(stderr, "[neg(%s) < %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(1), bool_to_str(result_lt_1));
// neg(a) vs. b
if (!!result_lt_1 != (samples[i].rel_np==BIGUINT_LT)) {
fprintf(stderr, "[neg(%s) < %s] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel_np==BIGUINT_LT), bool_to_str(result_lt_1));
fail = 1;
}
if (result_gt_1) { // a not negative value cannot be less than a not positive value
fprintf(stderr, "[%s < neg(%s)] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(0), bool_to_str(result_gt_1));
if (!!result_gt_1 != (samples[i].rel_np==BIGUINT_GT)) { // a not negative value cannot be less than a not positive value
fprintf(stderr, "[%s < neg(%s)] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel_np==BIGUINT_GT), bool_to_str(result_gt_1));
fail = 1;
}

if (result_lt_2) { // a not negative value cannot be less than a not positive value
fprintf(stderr, "[%s < neg(%s)] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(0), bool_to_str(result_lt_2));
// a vs. neg(b)
if (!!result_lt_2 != (samples[i].rel_pn==BIGUINT_LT)) {
fprintf(stderr, "[%s < neg(%s)] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel_pn==BIGUINT_LT), bool_to_str(result_lt_2));
fail = 1;
}
if (!result_gt_2 && !(za && zb)) { // a not positive value is less than a not negative value, unless they both are 0
fprintf(stderr, "[neg(%s) < %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(1), bool_to_str(result_gt_2));
if (!!result_gt_2 != (samples[i].rel_pn==BIGUINT_GT)) {
fprintf(stderr, "[neg(%s) < %s] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel_pn==BIGUINT_GT), bool_to_str(result_gt_2));
fail = 1;
}

// original
if (!!result_lt_3 != (samples[i].rel==BIGUINT_GT)) { // if a gt b, then neg(a) lt neg(b)
fprintf(stderr, "[neg(%s) < neg(%s)] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel==BIGUINT_LT), bool_to_str(result_lt_3));
// neg(a) vs. neg(b)
if (!!result_lt_3 != (samples[i].rel_nn==BIGUINT_LT)) {
fprintf(stderr, "[neg(%s) < neg(%s)] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel_nn==BIGUINT_LT), bool_to_str(result_lt_3));
fail = 1;
}
if (!!result_gt_3 != (samples[i].rel==BIGUINT_LT)) { // if a lt b, then neg(a) gt neg(b)
fprintf(stderr, "[neg(%s) < neg(%s)] expected: [%s], actual [%s]\n", sample_left->str, sample_right->str, bool_to_str(samples[i].rel==BIGUINT_GT), bool_to_str(result_gt_3));
if (!!result_gt_3 != (samples[i].rel_nn==BIGUINT_GT)) {
fprintf(stderr, "[neg(%s) < neg(%s)] expected: [%s], actual [%s]\n", sample_right->str, sample_left->str, bool_to_str(samples[i].rel_nn==BIGUINT_GT), bool_to_str(result_gt_3));
fail = 1;
}
++run_cnt;
Expand Down
89 changes: 88 additions & 1 deletion tests/biguint128_mul_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ const CStr hex_samples[][3] = {
};
int hex_sample_len = sizeof(hex_samples) / (sizeof(hex_samples[0]));

const CStr bigint_dec_samples[][5] = {
{ STR("-10"), STR("10"), STR("-100"), STR("-105"), STR("-5")},
{ STR("10"), STR("-10"), STR("-100"), STR("-103"), STR("-3")},
{ STR("-10"), STR("-10"), STR("100"), STR("102"), STR("2")},
};
int bigint_dec_sample_len = sizeof(bigint_dec_samples) / (sizeof(bigint_dec_samples[0]));

bool test_mul0() {
bool fail = false;
for (int i=0; i<hex_sample_len; ++i) {
Expand Down Expand Up @@ -208,7 +215,7 @@ bool test_div1() {
BigUInt128 val[3];
BigUInt128 *a=&val[0];
BigUInt128 *b=&val[2];
if (!readhex_more_cstr_biguint128(val, hex_samples[i],3)) {
if (!readhex_more_cstr_biguint128(val, hex_samples[i], 3)) {
continue;
}
if (biguint128_eq(a, &zero)) {
Expand Down Expand Up @@ -238,6 +245,83 @@ bool test_div1() {
return !fail;
}


bool test_mul_signed0() {
bool fail = false;
for (int i=0; i<bigint_dec_sample_len; ++i) {
BigUInt128 val[3];
if (!readdec_more_cstr_bigint128(val, bigint_dec_samples[i], 3)) {
continue;
}

BigUInt128 res_mul = biguint128_mul(&val[0], &val[1]);
BigUIntPair128 res_div = bigint128_div(&val[2], &val[1]);

buint_bool result_mul_eq = biguint128_eq(&val[2], &res_mul);
buint_bool result_div_eq = biguint128_eq(&val[0], &res_div.first);

if (!result_mul_eq) {
char buffer[4][HEX_BIGUINTLEN + 1];
buffer[0][bigint128_print_dec(&val[0], buffer[0], HEX_BIGUINTLEN)]=0;
buffer[1][bigint128_print_dec(&val[1], buffer[1], HEX_BIGUINTLEN)]=0;
buffer[2][bigint128_print_dec(&val[2], buffer[2], HEX_BIGUINTLEN)]=0;
buffer[3][bigint128_print_dec(&res_mul, buffer[3], HEX_BIGUINTLEN)]=0;
fprintf(stderr, "[%s * %s] -- expected: [%s], actual [%s]\n", buffer[0], buffer[1], buffer[2], buffer[3]);
fail = true;
}

if (!result_div_eq) {
char buffer[4][HEX_BIGUINTLEN + 1];
buffer[0][bigint128_print_dec(&val[2], buffer[0], HEX_BIGUINTLEN)]=0;
buffer[1][bigint128_print_dec(&val[1], buffer[1], HEX_BIGUINTLEN)]=0;
buffer[2][bigint128_print_dec(&val[0], buffer[2], HEX_BIGUINTLEN)]=0;
buffer[3][bigint128_print_dec(&res_div.first, buffer[3], HEX_BIGUINTLEN)]=0;
fprintf(stderr, "[%s / %s] -- expected: [%s], actual [%s]\n", buffer[0], buffer[1], buffer[2], buffer[3]);
fail = true;
}
}

return !fail;
}

bool test_div_signed0() {
bool fail = false;
for (int i=0; i<bigint_dec_sample_len; ++i) {
BigUInt128 val[5];
if (!readdec_more_cstr_bigint128(val, bigint_dec_samples[i], 5)) {
continue;
}

BigUIntPair128 res_div = bigint128_div(&val[3], &val[1]);

buint_bool result_div_eq = biguint128_eq(&val[0], &res_div.first);
buint_bool result_rem_eq = biguint128_eq(&val[4], &res_div.second);

if (!result_rem_eq) {
char buffer[4][HEX_BIGUINTLEN + 1];
buffer[0][bigint128_print_dec(&val[3], buffer[0], HEX_BIGUINTLEN)]=0;
buffer[1][bigint128_print_dec(&val[2], buffer[1], HEX_BIGUINTLEN)]=0;
buffer[2][bigint128_print_dec(&val[4], buffer[2], HEX_BIGUINTLEN)]=0;
buffer[3][bigint128_print_dec(&res_div.second, buffer[3], HEX_BIGUINTLEN)]=0;
fprintf(stderr, "[%s - %s] (a - b(a/b)) -- expected: [%s], actual [%s]\n", buffer[0], buffer[1], buffer[2], buffer[3]);
fail = true;
}

if (!result_div_eq) {
char buffer[4][HEX_BIGUINTLEN + 1];
buffer[0][bigint128_print_dec(&val[3], buffer[0], HEX_BIGUINTLEN)]=0;
buffer[1][bigint128_print_dec(&val[1], buffer[1], HEX_BIGUINTLEN)]=0;
buffer[2][bigint128_print_dec(&val[0], buffer[2], HEX_BIGUINTLEN)]=0;
buffer[3][bigint128_print_dec(&res_div.first, buffer[3], HEX_BIGUINTLEN)]=0;
fprintf(stderr, "[%s / %s] -- expected: [%s], actual [%s]\n", buffer[0], buffer[1], buffer[2], buffer[3]);
fail = true;
}
}

return !fail;
}


int main(int argc, char **argv) {

init_testvalues();
Expand All @@ -251,5 +335,8 @@ int main(int argc, char **argv) {
assert(test_div0());
assert(test_div1());

assert(test_mul_signed0());
assert(test_div_signed0());

return 0;
}
23 changes: 22 additions & 1 deletion tests/test_common128.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,24 @@ bool readhex_biguint128(BigUInt128 *result, const char* const hexstr, size_t hex
return true;
}

bool readdec_bigint128(BigUInt128 *result, const char* const decstr, size_t declen) {
if (declen == 0 || DEC_BIGINTLEN < declen) {
return false;
}
*result = bigint128_ctor_deccstream(decstr, declen);
return true;
}


bool readhex_cstr_biguint128(BigUInt128 *result, const CStr* const hex) {
return readhex_biguint128(result, hex->str, hex->len);
}

bool readdec_cstr_bigint128(BigUInt128 *result, const CStr* const dec) {
return readdec_bigint128(result, dec->str, dec->len);
}


bool readhex_more_cstr_biguint128(BigUInt128 *result_arr, const CStr* const hex_arr, size_t num) {
bool retv = true;
for (size_t i = 0; i < num; ++i) {
Expand All @@ -46,6 +60,13 @@ bool readhex_more_cstr_biguint128(BigUInt128 *result_arr, const CStr* const hex_
return retv;
}

bool readdec_more_cstr_bigint128(BigUInt128 *result_arr, const CStr * const dec_arr, size_t num) {
bool retv = true;
for (size_t i = 0; i < num; ++i) {
retv &= readdec_cstr_bigint128(result_arr + i, dec_arr + i);
}
return retv;
}

void fprint_funres_buint128_x_bsz_buint128(
FILE *out,
Expand All @@ -71,4 +92,4 @@ void fprint_funres_buint128_x_bsz_bb(
buffer[0][biguint128_print_hex(a, buffer[0], HEX_BIGUINTLEN)]=0;
fprintf(out, "%s(%s,%" PRIbuint_size_t ") -- expected: [%u], actual [%u]\n",
funname, buffer[0], b, expected, actual);
}
}
3 changes: 2 additions & 1 deletion tests/test_common128.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ void init_testvalues();
BigUInt128 negate_bigint128(const BigUInt128 *src);
bool readhex_biguint128(BigUInt128 *result, const char * const hexstr, size_t hexlen);
bool readhex_cstr_biguint128(BigUInt128 *result, const CStr * const hexstr);
bool readhex_more_cstr_biguint128(BigUInt128 *result, const CStr * const hexstr, size_t num);
bool readhex_more_cstr_biguint128(BigUInt128 *result_arr, const CStr * const hex_arr, size_t num);
bool readdec_more_cstr_bigint128(BigUInt128 *result_arr, const CStr * const dec_arr, size_t num);

void fprint_funres_buint128_x_bsz_buint128(FILE *out, const char *funname, const BigUInt128 *a, buint_size_t b, const BigUInt128 *expected, const BigUInt128 *actual);
void fprint_funres_buint128_x_bsz_bb(FILE *out, const char *funname, const BigUInt128 *a, buint_size_t b, buint_bool expected, buint_bool actual);
Expand Down

0 comments on commit ec5d47e

Please sign in to comment.