Improve big integer tests, fix bugs, add quick digit multiplication

This commit is contained in:
2024-06-21 23:14:14 +03:00
parent 4c77ce8fe3
commit 87b34d57be
4 changed files with 831 additions and 232 deletions

View File

@@ -84,6 +84,10 @@ int bh_bigint_mul(bh_bigint_t *to,
bh_bigint_t *left, bh_bigint_t *left,
bh_bigint_t *right); bh_bigint_t *right);
int bh_bigint_mul_digit(bh_bigint_t *to,
bh_bigint_t *left,
bh_int16_t right);
int bh_bigint_pow(bh_bigint_t *to, int bh_bigint_pow(bh_bigint_t *to,
bh_bigint_t *from, bh_bigint_t *from,
bh_uint32_t power); bh_uint32_t power);

View File

@@ -5,3 +5,4 @@
#include <bh/internal/config.h> #include <bh/internal/config.h>
#endif /* BH_INTERNAL_H */ #endif /* BH_INTERNAL_H */

View File

@@ -496,9 +496,14 @@ int bh_bigint_add(bh_bigint_t *to,
else else
code = bh_bigint_sub_base(to, most, least); code = bh_bigint_sub_base(to, most, least);
/* Set result sign */
if (!code) if (!code)
{
/* Set result sign or zero */
if (to->size)
to->type = type; to->type = type;
else
to->type = 0;
}
/* Return result code */ /* Return result code */
return code; return code;
@@ -538,9 +543,14 @@ int bh_bigint_sub(bh_bigint_t *to,
else else
code = bh_bigint_add_base(to, most, least); code = bh_bigint_add_base(to, most, least);
/* Set result sign */
if (!code) if (!code)
{
/* Set result sign or zero */
if (to->size)
to->type = type; to->type = type;
else
to->type = 0;
}
/* Return result code */ /* Return result code */
return code; return code;
@@ -639,6 +649,73 @@ int bh_bigint_mul(bh_bigint_t *to,
return BH_OK; return BH_OK;
} }
int bh_bigint_mul_digit(bh_bigint_t *to,
bh_bigint_t *left,
bh_int16_t right)
{
BH_BIGINT_TYPE carry;
BH_BIGINT_TMP tmp;
size_t i, size;
/* Shortcut - one of the arguments has error flag set */
if (left->error)
{
to->error = 1;
return BH_ERROR;
}
/* Clear up result error flag */
to->error = 0;
/* Shortcut - multiplication by zero */
if (left->type == 0 || right == 0)
{
to->type = 0;
to->size = 0;
return BH_OK;
}
/* Reserve space for result */
if (to->capacity < (left->size + 1))
{
if (bh_bigint_reserve(to, left->size + 1))
{
to->error = 1;
return BH_OOM;
}
}
/* Determine sign */
if ((left->type > 0 && right < 0) || (left->type < 0 && right > 0))
to->type = -1;
else
to->type = 1;
if (right < 0)
right = -right;
/* Prepare variables */
carry = 0;
/* Multiplication loop */
for (i = 0; i < left->size; i++)
{
tmp = (BH_BIGINT_TMP)left->data[i] * (BH_BIGINT_TMP)right + carry;
carry = tmp >> BH_BIGINT_BITS;
to->data[i] = tmp & BH_BIGINT_MASK;
}
to->data[i] = carry;
/* Truncate multiplication result size */
size = left->size + 1;
while (size && !to->data[size - 1]) size--;
/* Update size */
to->size = size;
return BH_OK;
}
int bh_bigint_pow(bh_bigint_t *to, int bh_bigint_pow(bh_bigint_t *to,
bh_bigint_t *from, bh_bigint_t *from,
bh_uint32_t power) bh_uint32_t power)
@@ -732,7 +809,7 @@ int bh_bigint_powm(bh_bigint_t *to,
code = BH_OK; code = BH_OK;
/* Shortcut - one of the arguments has error flag set */ /* Shortcut - one of the arguments has error flag set */
if (left->error || right->error) if (left->error || right->error || mod->error)
{ {
to->error = 1; to->error = 1;
return BH_ERROR; return BH_ERROR;
@@ -993,7 +1070,8 @@ static int bh_bigint_div_base(bh_bigint_t *quotient,
} }
/* Calculate remainder */ /* Calculate remainder */
bh_bigint_sub(remainder, remainder, tmp); /* Prevent using addition logic and use subtraction */
bh_bigint_sub_base(remainder, remainder, tmp);
if (!nleft->size) if (!nleft->size)
break; break;
@@ -1020,6 +1098,9 @@ finish:
return code; return code;
} }
/**
* This follows C99 model (a/b)*b + a%b
*/
int bh_bigint_divmod(bh_bigint_t *quotient, int bh_bigint_divmod(bh_bigint_t *quotient,
bh_bigint_t *remainder, bh_bigint_t *remainder,
bh_bigint_t *left, bh_bigint_t *left,
@@ -1111,6 +1192,9 @@ int bh_bigint_divmod(bh_bigint_t *quotient,
code = bh_bigint_div_base(quotient, tmp, left, right, &shift); code = bh_bigint_div_base(quotient, tmp, left, right, &shift);
if (!code) if (!code)
{ {
/* Remainder should use sign of the left operand */
tmp->type = left->type;
/* If remainder required - normilize it */ /* If remainder required - normilize it */
if (tmp == remainder) if (tmp == remainder)
bh_bigint_rsh(remainder, remainder, shift); bh_bigint_rsh(remainder, remainder, shift);
@@ -1358,10 +1442,16 @@ int bh_bigint_or(bh_bigint_t *to,
to->data[i] = tmp; to->data[i] = tmp;
} }
/* Shrink size */
while (size && !to->data[size - 1]) size--;
/* Update fields */ /* Update fields */
to->type = 1; to->type = 1;
to->size = size; to->size = size;
if (!size)
to->type = 0;
return BH_OK; return BH_OK;
} }
@@ -1401,10 +1491,16 @@ int bh_bigint_and(bh_bigint_t *to,
to->data[i] = tmp; to->data[i] = tmp;
} }
/* Shrink size */
while (size && !to->data[size - 1]) size--;
/* Update fields */ /* Update fields */
to->type = 1; to->type = 1;
to->size = size; to->size = size;
if (!size)
to->type = 0;
return BH_OK; return BH_OK;
} }
@@ -1444,10 +1540,16 @@ int bh_bigint_xor(bh_bigint_t *to,
to->data[i] = tmp; to->data[i] = tmp;
} }
/* Shrink size */
while (size && !to->data[size - 1]) size--;
/* Update fields */ /* Update fields */
to->type = 1; to->type = 1;
to->size = size; to->size = size;
if (!size)
to->type = 0;
return BH_OK; return BH_OK;
} }
@@ -1472,10 +1574,7 @@ int bh_bigint_negate(bh_bigint_t *to,
} }
/* Change the sign */ /* Change the sign */
if (to->type < 0) to->type = 0 - to->type;
to->type = 1;
else if (to->type > 0)
to->type = -1;
return BH_OK; return BH_OK;
} }

File diff suppressed because it is too large Load Diff