Improve big integer tests, fix bugs, add quick digit multiplication
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -4,4 +4,5 @@
|
|||||||
#include <bh/bh.h>
|
#include <bh/bh.h>
|
||||||
#include <bh/internal/config.h>
|
#include <bh/internal/config.h>
|
||||||
|
|
||||||
#endif /* BH_INTERNAL_H */
|
#endif /* BH_INTERNAL_H */
|
||||||
|
|
||||||
|
|||||||
149
src/bigint.c
149
src/bigint.c
@@ -67,7 +67,7 @@ static size_t bh_bigint_type_log2(BH_BIGINT_TYPE x)
|
|||||||
tmp = (x >> (BH_BIGINT_BITS - 7)) & 0xFF;
|
tmp = (x >> (BH_BIGINT_BITS - 7)) & 0xFF;
|
||||||
if (tmp)
|
if (tmp)
|
||||||
return ((BH_BIGINT_BITS + 1) - 8 * (i + 1)) + lookup[tmp];
|
return ((BH_BIGINT_BITS + 1) - 8 * (i + 1)) + lookup[tmp];
|
||||||
|
|
||||||
x <<= 8;
|
x <<= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ static int bh_bigint_add_base(bh_bigint_t *to,
|
|||||||
to->size = most->size + 1;
|
to->size = most->size + 1;
|
||||||
else
|
else
|
||||||
to->size = most->size;
|
to->size = most->size;
|
||||||
|
|
||||||
return BH_OK;
|
return BH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,7 +415,7 @@ static int bh_bigint_sub_base(bh_bigint_t *to,
|
|||||||
{
|
{
|
||||||
BH_BIGINT_TYPE carry, tmp;
|
BH_BIGINT_TYPE carry, tmp;
|
||||||
size_t size, i;
|
size_t size, i;
|
||||||
|
|
||||||
/* Clear up result error flag */
|
/* Clear up result error flag */
|
||||||
to->error = 0;
|
to->error = 0;
|
||||||
|
|
||||||
@@ -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)
|
||||||
to->type = type;
|
{
|
||||||
|
/* Set result sign or zero */
|
||||||
|
if (to->size)
|
||||||
|
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)
|
||||||
to->type = type;
|
{
|
||||||
|
/* Set result sign or zero */
|
||||||
|
if (to->size)
|
||||||
|
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;
|
||||||
@@ -740,7 +817,7 @@ int bh_bigint_powm(bh_bigint_t *to,
|
|||||||
|
|
||||||
/* Clear up result error flag */
|
/* Clear up result error flag */
|
||||||
to->error = 0;
|
to->error = 0;
|
||||||
|
|
||||||
/* Shortcut - power is equal to 0 */
|
/* Shortcut - power is equal to 0 */
|
||||||
if (bh_bigint_is_zero(right))
|
if (bh_bigint_is_zero(right))
|
||||||
return bh_bigint_set_int(to, 1);
|
return bh_bigint_set_int(to, 1);
|
||||||
@@ -752,7 +829,7 @@ int bh_bigint_powm(bh_bigint_t *to,
|
|||||||
/* Shortcut - power is negative */
|
/* Shortcut - power is negative */
|
||||||
if (bh_bigint_is_negative(right))
|
if (bh_bigint_is_negative(right))
|
||||||
return bh_bigint_clear(to);
|
return bh_bigint_clear(to);
|
||||||
|
|
||||||
/* Figure out result sign */
|
/* Figure out result sign */
|
||||||
if (left->type < 0 && right->data[0] & 0x1)
|
if (left->type < 0 && right->data[0] & 0x1)
|
||||||
type = -1;
|
type = -1;
|
||||||
@@ -816,7 +893,7 @@ int bh_bigint_powm(bh_bigint_t *to,
|
|||||||
bh_bigint_mul(base, base, base);
|
bh_bigint_mul(base, base, base);
|
||||||
bh_bigint_mod(base, base, mod);
|
bh_bigint_mod(base, base, mod);
|
||||||
bh_bigint_rsh(exponent, exponent, 1);
|
bh_bigint_rsh(exponent, exponent, 1);
|
||||||
|
|
||||||
/* Stop if error occured */
|
/* Stop if error occured */
|
||||||
if (base->error || result->error)
|
if (base->error || result->error)
|
||||||
{
|
{
|
||||||
@@ -848,14 +925,14 @@ static BH_BIGINT_TYPE bh_bigint_div_guess(bh_bigint_t *left,
|
|||||||
bh_bigint_t *right)
|
bh_bigint_t *right)
|
||||||
{
|
{
|
||||||
BH_BIGINT_TMP tmp;
|
BH_BIGINT_TMP tmp;
|
||||||
|
|
||||||
/* Left is bigger then right */
|
/* Left is bigger then right */
|
||||||
if (bh_bigint_equal_mod(left, right) < 0)
|
if (bh_bigint_equal_mod(left, right) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Make a guess */
|
/* Make a guess */
|
||||||
tmp = left->data[left->size - 1];
|
tmp = left->data[left->size - 1];
|
||||||
|
|
||||||
if (left->size != right->size)
|
if (left->size != right->size)
|
||||||
tmp = (tmp << BH_BIGINT_BITS) + left->data[left->size - 2];
|
tmp = (tmp << BH_BIGINT_BITS) + left->data[left->size - 2];
|
||||||
|
|
||||||
@@ -959,7 +1036,7 @@ static int bh_bigint_div_base(bh_bigint_t *quotient,
|
|||||||
}
|
}
|
||||||
nleft->size--;
|
nleft->size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
/* Make a guess at what first digit of quotient should be */
|
/* Make a guess at what first digit of quotient should be */
|
||||||
@@ -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,10 +1192,13 @@ 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);
|
||||||
|
|
||||||
/* Fix the sign */
|
/* Fix the sign */
|
||||||
if (quotient)
|
if (quotient)
|
||||||
quotient->type = type;
|
quotient->type = type;
|
||||||
@@ -1145,7 +1229,7 @@ int bh_bigint_lsh(bh_bigint_t *to,
|
|||||||
bh_uint32_t shift)
|
bh_uint32_t shift)
|
||||||
{
|
{
|
||||||
size_t i, bits, blocks;
|
size_t i, bits, blocks;
|
||||||
BH_BIGINT_TYPE tmp;
|
BH_BIGINT_TYPE tmp;
|
||||||
|
|
||||||
/* Shortcut - one of the arguments has error flag set */
|
/* Shortcut - one of the arguments has error flag set */
|
||||||
if (left->error)
|
if (left->error)
|
||||||
@@ -1255,7 +1339,7 @@ int bh_bigint_rsh(bh_bigint_t *to,
|
|||||||
/* Calculate distance in blocks and bits */
|
/* Calculate distance in blocks and bits */
|
||||||
blocks = shift / BH_BIGINT_BITS;
|
blocks = shift / BH_BIGINT_BITS;
|
||||||
bits = shift % BH_BIGINT_BITS;
|
bits = shift % BH_BIGINT_BITS;
|
||||||
|
|
||||||
/* Shortcut - shift is bigger than value or value is 0 */
|
/* Shortcut - shift is bigger than value or value is 0 */
|
||||||
if (left->type == 0 || left->size < blocks)
|
if (left->type == 0 || left->size < blocks)
|
||||||
{
|
{
|
||||||
@@ -1302,7 +1386,7 @@ int bh_bigint_rsh(bh_bigint_t *to,
|
|||||||
return BH_OOM;
|
return BH_OOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main loop for aligned shift */
|
/* Main loop for aligned shift */
|
||||||
for (i = 0; i < left->size - blocks; i++)
|
for (i = 0; i < left->size - blocks; i++)
|
||||||
to->data[i] = left->data[i + blocks];
|
to->data[i] = left->data[i + blocks];
|
||||||
@@ -1312,7 +1396,7 @@ int bh_bigint_rsh(bh_bigint_t *to,
|
|||||||
i = left->size - blocks;
|
i = left->size - blocks;
|
||||||
while (i && !to->data[i - 1]) i--;
|
while (i && !to->data[i - 1]) i--;
|
||||||
|
|
||||||
/* Update fields */
|
/* Update fields */
|
||||||
to->size = i;
|
to->size = i;
|
||||||
to->type = left->type;
|
to->type = left->type;
|
||||||
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1555,4 +1654,4 @@ size_t bh_bigint_log2(bh_bigint_t *bigint)
|
|||||||
|
|
||||||
result = bh_bigint_type_log2(bigint->data[bigint->size - 1]);
|
result = bh_bigint_type_log2(bigint->data[bigint->size - 1]);
|
||||||
return result + (bigint->size - 1) * BH_BIGINT_BITS;
|
return result + (bigint->size - 1) * BH_BIGINT_BITS;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user