1311 lines
52 KiB
C
1311 lines
52 KiB
C
/*
|
|
FILE NAME: arithm.c
|
|
|
|
TITLE: Package for arbitrary precision integer arithmetic
|
|
|
|
DESCRIPTION: This abstract data implements arbitrary precision
|
|
integer and unsigned integer numbers by machine independent
|
|
way. The implementation of the package functions are not
|
|
sufficiently efficient in order to use for run-time. The
|
|
package functions are oriented to implement constant-folding in
|
|
compilers. This package is necessary because host machine may
|
|
not support such arithmetic for target machine. For example,
|
|
VAX does not support does not support more 32-bits integer
|
|
numbers arithmetic. The numbers are represented by bytes in
|
|
big endian mode, negative integer numbers are represented in
|
|
complementary code. All sizes are given in bytes and must be
|
|
positive. Results of executions of all functions can coincide
|
|
with a operand(s). All functions of addition, subtraction,
|
|
multiplication, division, evaluation of remainder, shift,
|
|
changing size and transformation of string into number fix
|
|
overflow. The overflow is fixed when result can not be
|
|
represented by number of given size.
|
|
|
|
*/
|
|
|
|
#include "arithm.h"
|
|
#include "ammunition_string.h"
|
|
|
|
/* This variable can have only two values 0 or 1. The value `1'
|
|
corresponds to overflow. The variable value are modified by all
|
|
functions of addition, subtract, multiplication, division,
|
|
evaluation of remainder, shift, changing size and transformation of
|
|
string into number fix overflow. */
|
|
|
|
// Wasm loop bounds
|
|
|
|
__attribute__((import_module("__pragma"), import_name("loopbound"))) extern void
|
|
__pragma_loopbound(unsigned int min_bound, unsigned int max_bound);
|
|
|
|
int ammunition_overflow_bit;
|
|
|
|
/* The following function adds unsigned integers. The function
|
|
returns 1 if unsigned integer overflow is fixed, 0 otherwise.
|
|
Result can be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_add_unsigned_integer_without_overflow_reaction(int size,
|
|
const void *op1,
|
|
const void *op2,
|
|
void *result) {
|
|
int digit_num;
|
|
int carry;
|
|
unsigned int sum;
|
|
__pragma_loopbound(4, 4);
|
|
for (digit_num = size - 1, carry = 0; digit_num >= 0; digit_num--) {
|
|
sum = (((unsigned char *) op1)[digit_num] +
|
|
((unsigned char *) op2)[digit_num] + carry);
|
|
if (sum > UCHAR_MAX) {
|
|
sum -= UCHAR_MAX + 1;
|
|
carry = 1;
|
|
} else
|
|
carry = 0;
|
|
((unsigned char *) result)[digit_num] = sum;
|
|
}
|
|
return carry != 0;
|
|
}
|
|
|
|
/* The following function adds unsigned integers. The function
|
|
returns 1 if unsigned integer overflow (the first operand is less
|
|
than the second) is fixed, 0 otherwise. Result can be placed in
|
|
any operand. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_subtract_unsigned_integer_without_overflow_reaction(int size,
|
|
const void *op1,
|
|
const void *op2,
|
|
void *result) {
|
|
int digit_num;
|
|
int carry;
|
|
int subtraction;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (digit_num = size - 1, carry = 0; digit_num >= 0; digit_num--) {
|
|
subtraction = (((unsigned char *) op1)[digit_num] -
|
|
((unsigned char *) op2)[digit_num] - carry);
|
|
if (subtraction < 0) {
|
|
subtraction += UCHAR_MAX + 1;
|
|
carry = 1;
|
|
} else
|
|
carry = 0;
|
|
((unsigned char *) result)[digit_num] = subtraction;
|
|
}
|
|
return carry != 0;
|
|
}
|
|
|
|
/* The following function makes complementary code of number. Result
|
|
can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_make_complementary_code(int size, const void *operand,
|
|
void *result) {
|
|
int digit_num;
|
|
int carry;
|
|
int subtraction;
|
|
|
|
__pragma_loopbound(2, 6);
|
|
for (digit_num = size - 1, carry = 0; digit_num >= 0; digit_num--) {
|
|
subtraction = (0 - ((unsigned char *) operand)[digit_num] - carry);
|
|
if (subtraction != 0) {
|
|
subtraction += UCHAR_MAX + 1;
|
|
carry = 1;
|
|
} else
|
|
carry = 0;
|
|
((unsigned char *) result)[digit_num] = subtraction;
|
|
}
|
|
}
|
|
|
|
/* The following function multiplys unsigned integer by digit (byte
|
|
size). The function returns 1 if unsigned integer overflow is
|
|
fixed, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction(
|
|
int size, void *operand, unsigned int digit) {
|
|
int digit_num;
|
|
unsigned int carry;
|
|
unsigned int sum;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (digit_num = size - 1, carry = 0; digit_num >= 0; digit_num--) {
|
|
sum = (((unsigned char *) operand)[digit_num] * digit + carry);
|
|
if (sum > UCHAR_MAX) {
|
|
carry = sum / (UCHAR_MAX + 1);
|
|
sum %= UCHAR_MAX + 1;
|
|
} else
|
|
carry = 0;
|
|
((unsigned char *) operand)[digit_num] = sum;
|
|
}
|
|
return carry != 0;
|
|
}
|
|
|
|
/* Originally reaction on all integer and unsigned integer overflow is
|
|
equal to the following function. The function does nothing. */
|
|
|
|
void
|
|
ammunition_arithmetic_overflow_reaction(void) {}
|
|
|
|
/* Originally reaction on all integer and unsigned integer overflow is
|
|
equal to the following function. The function does nothing. */
|
|
|
|
void
|
|
ammunition_arithmetic_unsigned_overflow_reaction(void) {}
|
|
|
|
/* This page contains functions for arbitrary precision addition. */
|
|
|
|
/* The function adds unsigned integers and fixes overflow reaction if
|
|
it is needed. The function makes this with the aid of function
|
|
`add_unsigned_integer_without_overflow_reaction'. Result can be
|
|
placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_add_unsigned_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_overflow_bit =
|
|
ammunition_add_unsigned_integer_without_overflow_reaction(size, op1,
|
|
op2, result);
|
|
if (ammunition_overflow_bit != 0)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
|
|
/* The function adds integers and fixes overflow reaction if it is
|
|
needed. The function makes this with the aid of function
|
|
`add_unsigned_integer_without_overflow_reaction'. Result can be
|
|
placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_add_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int op1_sign;
|
|
int sign_equality;
|
|
|
|
op1_sign = INTEGER_SIGN(op1);
|
|
sign_equality = INTEGER_SIGN(op1) == INTEGER_SIGN(op2);
|
|
ammunition_add_unsigned_integer_without_overflow_reaction(size, op1, op2,
|
|
result);
|
|
ammunition_overflow_bit =
|
|
sign_equality && (op1_sign != INTEGER_SIGN(result));
|
|
if (ammunition_overflow_bit != 0)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
|
|
/* This page contains functions for arbitrary precision subtraction. */
|
|
|
|
/* The function subtracts unsigned integers and fixes overflow
|
|
reaction if it is needed. The function makes this with the aid of
|
|
function `subtract_unsigned_integer_without_overflow_reaction'.
|
|
Result can be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_subtract_unsigned_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_overflow_bit =
|
|
ammunition_subtract_unsigned_integer_without_overflow_reaction(
|
|
size, op1, op2, result);
|
|
if (ammunition_overflow_bit != 0)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
|
|
/* The function subtracts integers and fixes overflow reaction if it
|
|
is needed. The function makes this with the aid of function
|
|
`subtract_unsigned_integer_without_overflow_reaction'. Result can
|
|
be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_subtract_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int op1_sign;
|
|
int sign_unequality;
|
|
|
|
op1_sign = INTEGER_SIGN(op1);
|
|
sign_unequality = INTEGER_SIGN(op1) != INTEGER_SIGN(op2);
|
|
ammunition_subtract_unsigned_integer_without_overflow_reaction(size, op1,
|
|
op2, result);
|
|
ammunition_overflow_bit =
|
|
sign_unequality && (op1_sign != INTEGER_SIGN(result));
|
|
if (ammunition_overflow_bit != 0)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
|
|
/* This page contains functions for arbitrary precision multiplication. */
|
|
|
|
/* The following function multiplys unsigned integers. The function
|
|
returns 1 if unsigned integer overflow is fixed, 0 otherwise.
|
|
Result can be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_multiply_unsigned_integer_without_overflow_reaction(int size,
|
|
const void *op1,
|
|
const void *op2,
|
|
void *result) {
|
|
int op1_digit_num;
|
|
int op2_digit_num;
|
|
int carry;
|
|
unsigned long long int partial_sum;
|
|
int result_digit_number;
|
|
int overflow_flag;
|
|
unsigned char long_result[2 * MAX_INTEGER_OPERAND_SIZE];
|
|
|
|
ammunition_memset(long_result + size, 0, (size_t) size);
|
|
__pragma_loopbound(4, 4);
|
|
for (op2_digit_num = size - 1; op2_digit_num >= 0; op2_digit_num--) {
|
|
if (((unsigned char *) op2)[op2_digit_num] != 0) {
|
|
__pragma_loopbound(4, 4);
|
|
for (op1_digit_num = size - 1, carry = 0; op1_digit_num >= 0;
|
|
op1_digit_num--) {
|
|
partial_sum =
|
|
(((unsigned char *) op1)[op1_digit_num] *
|
|
((unsigned char *) op2)[op2_digit_num] +
|
|
long_result[op1_digit_num + op2_digit_num + 1] + carry);
|
|
long_result[op1_digit_num + op2_digit_num + 1] =
|
|
(unsigned char) (partial_sum % (UCHAR_MAX + 1));
|
|
carry = partial_sum / (UCHAR_MAX + 1);
|
|
}
|
|
long_result[op2_digit_num] = carry;
|
|
} else
|
|
long_result[op2_digit_num] = 0;
|
|
}
|
|
overflow_flag = 0;
|
|
__pragma_loopbound(0, 4);
|
|
for (result_digit_number = size - 1; result_digit_number >= 0;
|
|
result_digit_number--) {
|
|
if (long_result[result_digit_number] != 0) {
|
|
overflow_flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
ammunition_memcpy(result, long_result + size, (size_t) size);
|
|
return overflow_flag;
|
|
}
|
|
|
|
/* The following function multiplys unsigned integers and fixes
|
|
overflow reaction if it is needed. The function makes this with
|
|
the aid of function
|
|
`multiply_unsigned_integer_without_overflow_reaction'. Result can
|
|
be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_multiply_unsigned_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_overflow_bit =
|
|
ammunition_multiply_unsigned_integer_without_overflow_reaction(
|
|
size, op1, op2, result);
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
|
|
/* The function multiplys integers and fixes overflow reaction if it
|
|
is needed. The function makes this with the aid of function
|
|
`multiply_unsigned_integer_without_overflow_reaction'. Result can
|
|
be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_multiply_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int negative_result_flag;
|
|
unsigned char op1_complementary[MAX_INTEGER_OPERAND_SIZE];
|
|
unsigned char op2_complementary[MAX_INTEGER_OPERAND_SIZE];
|
|
unsigned const char *abs_op1;
|
|
unsigned const char *abs_op2;
|
|
int unsigned_result_sign;
|
|
|
|
negative_result_flag = INTEGER_SIGN(op1) != INTEGER_SIGN(op2);
|
|
if (INTEGER_SIGN(op1)) {
|
|
/* May be integer overflow. But result is correct because
|
|
it is unsigned. */
|
|
ammunition_make_complementary_code(size, op1, op1_complementary);
|
|
abs_op1 = (unsigned const char *) op1_complementary;
|
|
} else
|
|
abs_op1 = (unsigned const char *) op1;
|
|
if (INTEGER_SIGN(op2)) {
|
|
/* May be integer overflow. But result is correct because
|
|
it is unsigned. */
|
|
ammunition_make_complementary_code(size, op2, op2_complementary);
|
|
abs_op2 = (unsigned const char *) op2_complementary;
|
|
} else
|
|
abs_op2 = (unsigned const char *) op2;
|
|
ammunition_overflow_bit =
|
|
ammunition_multiply_unsigned_integer_without_overflow_reaction(
|
|
size, abs_op1, abs_op2, result);
|
|
unsigned_result_sign = INTEGER_SIGN(result);
|
|
if (negative_result_flag)
|
|
ammunition_make_complementary_code(size, result, result);
|
|
if (unsigned_result_sign &&
|
|
(!negative_result_flag || INTEGER_SIGN(result) != unsigned_result_sign))
|
|
/* Unsigned result can not be represented as integer. */
|
|
ammunition_overflow_bit = 1;
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
|
|
/* This page contains functions for arbitrary precision division. */
|
|
|
|
/* The following function divides unsigned integers. The function
|
|
returns 1 if unsigned integer overflow (division by zero) is fixed,
|
|
0 otherwise. Result can be placed in any operand. See algorithm
|
|
in Knuth's book. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_divide_unsigned_integer_without_overflow_reaction(int size,
|
|
const void *op1,
|
|
const void *op2,
|
|
void *result) {
|
|
int scaled_op1_digit_num;
|
|
unsigned int q_approximation;
|
|
int first_nonzero_digit_number;
|
|
int op2_digit_number;
|
|
unsigned int scale;
|
|
unsigned char scaled_op1[MAX_INTEGER_OPERAND_SIZE + 1];
|
|
unsigned char normalized_op2[MAX_INTEGER_OPERAND_SIZE];
|
|
unsigned char extended_normalized_op2[MAX_INTEGER_OPERAND_SIZE + 1];
|
|
|
|
__pragma_loopbound(3, 4);
|
|
for (op2_digit_number = 0; op2_digit_number < size; op2_digit_number++) {
|
|
if (((unsigned char *) op2)[op2_digit_number] != 0)
|
|
break;
|
|
}
|
|
first_nonzero_digit_number = op2_digit_number;
|
|
if (first_nonzero_digit_number == size) {
|
|
/* Zero divisor */
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
return 1 /* TRUE */;
|
|
} else if (first_nonzero_digit_number == size - 1) {
|
|
/* Division by digit. */
|
|
int digit_num;
|
|
int digit;
|
|
unsigned long long divisable;
|
|
unsigned long long remainder;
|
|
|
|
digit = ((unsigned char *) op2)[first_nonzero_digit_number];
|
|
ammunition_memcpy(result, op1, (size_t) size);
|
|
remainder = 0;
|
|
__pragma_loopbound(4, 4);
|
|
for (digit_num = 0; digit_num < size; digit_num++) {
|
|
divisable = (remainder * (UCHAR_MAX + 1) +
|
|
((unsigned char *) result)[digit_num]);
|
|
remainder = divisable % digit;
|
|
((unsigned char *) result)[digit_num] =
|
|
(unsigned char) (divisable / digit);
|
|
}
|
|
return 0 /* FALSE */;
|
|
}
|
|
/* Normalization of divisor. */
|
|
scale = (UCHAR_MAX + 1) / (((unsigned char *) op2)[op2_digit_number] + 1);
|
|
ammunition_memcpy(scaled_op1 + 1, op1, (size_t) size);
|
|
*scaled_op1 = 0;
|
|
|
|
ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction(
|
|
size + 1, scaled_op1, scale);
|
|
|
|
ammunition_memcpy(normalized_op2, op2, (size_t) size);
|
|
|
|
ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction(
|
|
size, normalized_op2, scale);
|
|
|
|
__pragma_loopbound(0, 0);
|
|
for (scaled_op1_digit_num = 0;
|
|
scaled_op1_digit_num <= first_nonzero_digit_number;
|
|
scaled_op1_digit_num++) {
|
|
/* Division of `scaled_op1[ scaled_op1_digit_number ]..scaled_op1[ size
|
|
]' by `normalized_op2[ first_nonzero_digit_number ]..normalized_op2[
|
|
size-1 ]' for evaluation of one digit of quotient `result[
|
|
size-1-first_nonzero_digit_number-scaled_op1_digit_number ]'.
|
|
*/
|
|
if (scaled_op1[scaled_op1_digit_num] ==
|
|
normalized_op2[first_nonzero_digit_number])
|
|
q_approximation = UCHAR_MAX;
|
|
else
|
|
q_approximation =
|
|
(scaled_op1[scaled_op1_digit_num] * (UCHAR_MAX + 1) +
|
|
scaled_op1[scaled_op1_digit_num + 1]) /
|
|
normalized_op2[first_nonzero_digit_number];
|
|
|
|
__pragma_loopbound(0, 0);
|
|
while (normalized_op2[first_nonzero_digit_number + 1] *
|
|
q_approximation >
|
|
(((unsigned long long int) scaled_op1[scaled_op1_digit_num] *
|
|
(UCHAR_MAX + 1) +
|
|
scaled_op1[scaled_op1_digit_num + 1] -
|
|
q_approximation * normalized_op2[first_nonzero_digit_number]) *
|
|
(UCHAR_MAX + 1) +
|
|
scaled_op1[scaled_op1_digit_num + 2]))
|
|
q_approximation--;
|
|
|
|
/* Multiply and subtract */
|
|
ammunition_memcpy(extended_normalized_op2 + 1,
|
|
normalized_op2 + first_nonzero_digit_number,
|
|
(size_t) (size - first_nonzero_digit_number));
|
|
*extended_normalized_op2 = 0;
|
|
ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction(
|
|
size - first_nonzero_digit_number + 1, extended_normalized_op2,
|
|
q_approximation);
|
|
if (ammunition_subtract_unsigned_integer_without_overflow_reaction(
|
|
size - first_nonzero_digit_number + 1,
|
|
scaled_op1 + scaled_op1_digit_num, extended_normalized_op2,
|
|
scaled_op1 + scaled_op1_digit_num)) {
|
|
/* Negative result. Compensation by addition. */
|
|
q_approximation--;
|
|
ammunition_memcpy(extended_normalized_op2 + 1,
|
|
normalized_op2 + first_nonzero_digit_number,
|
|
(size_t) (size - first_nonzero_digit_number));
|
|
*extended_normalized_op2 = 0;
|
|
|
|
ammunition_add_unsigned_integer_without_overflow_reaction(
|
|
size - first_nonzero_digit_number + 1,
|
|
scaled_op1 + scaled_op1_digit_num, extended_normalized_op2,
|
|
scaled_op1 + scaled_op1_digit_num);
|
|
}
|
|
((unsigned char *) result)[size - 1 - first_nonzero_digit_number +
|
|
scaled_op1_digit_num] = q_approximation;
|
|
}
|
|
ammunition_memset(result, 0,
|
|
(size_t) (size - 1 - first_nonzero_digit_number));
|
|
return 0 /* TRUE */;
|
|
}
|
|
|
|
/* The function divides unsigned integers and fixes overflow reaction
|
|
if it is needed. The function makes this with the aid of function
|
|
`divide_unsigned_integer_without_overflow_reaction'. Result can be
|
|
placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_divide_unsigned_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_overflow_bit =
|
|
ammunition_divide_unsigned_integer_without_overflow_reaction(
|
|
size, op1, op2, result);
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
|
|
/* The function divides integers and fixes overflow reaction if it is
|
|
needed. The function makes this with the aid of function
|
|
`divide_unsigned_integer_without_overflow_reaction'. Result can be
|
|
placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_divide_integer(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int negative_result_flag;
|
|
unsigned char op1_complementary[MAX_INTEGER_OPERAND_SIZE];
|
|
unsigned char op2_complementary[MAX_INTEGER_OPERAND_SIZE];
|
|
unsigned const char *abs_op1;
|
|
unsigned const char *abs_op2;
|
|
int unsigned_result_sign;
|
|
|
|
negative_result_flag = INTEGER_SIGN(op1) != INTEGER_SIGN(op2);
|
|
if (INTEGER_SIGN(op1)) {
|
|
/* May be integer overflow for minimal int. But result is correct
|
|
because it is unsigned. */
|
|
ammunition_make_complementary_code(size, op1, op1_complementary);
|
|
abs_op1 = (unsigned const char *) op1_complementary;
|
|
} else
|
|
abs_op1 = (unsigned const char *) op1;
|
|
if (INTEGER_SIGN(op2)) {
|
|
/* May be integer overflow for minimal int. But result is correct
|
|
because it is unsigned. */
|
|
ammunition_make_complementary_code(size, op2, op2_complementary);
|
|
abs_op2 = (unsigned const char *) op2_complementary;
|
|
} else
|
|
abs_op2 = (unsigned const char *) op2;
|
|
ammunition_overflow_bit =
|
|
ammunition_divide_unsigned_integer_without_overflow_reaction(
|
|
size, abs_op1, abs_op2, result);
|
|
unsigned_result_sign = INTEGER_SIGN(result);
|
|
if (negative_result_flag)
|
|
ammunition_make_complementary_code(size, result, result);
|
|
if (unsigned_result_sign &&
|
|
(!negative_result_flag || INTEGER_SIGN(result) != unsigned_result_sign))
|
|
/* Unsigned result can not be represented as integer. */
|
|
ammunition_overflow_bit = 1;
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
|
|
/* This page contains functions for arbitrary precision evaluation of
|
|
remainder. */
|
|
|
|
/* The function evaluates remainder of division of unsigned integers
|
|
as `op1 - (op1/op2)*op2' and fixes overflow reaction if it is
|
|
needed. Result can be placed in any operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_remainder(int size, const void *op1,
|
|
const void *op2, void *result) {
|
|
unsigned char temporary[MAX_INTEGER_OPERAND_SIZE];
|
|
|
|
ammunition_divide_unsigned_integer(size, op1, op2, temporary);
|
|
if (ammunition_overflow_bit)
|
|
/* Reaction on zero is called from `divide_unsigned_integer'. */
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
else {
|
|
ammunition_multiply_unsigned_integer(size, temporary, op2, temporary);
|
|
ammunition_subtract_unsigned_integer(size, op1, temporary, result);
|
|
}
|
|
}
|
|
|
|
/* This page contains functions for arbitrary precision number shifts. */
|
|
|
|
/* This function makes right shift of unsigned integer of given size
|
|
on given number of bits. If number of bits is negative the
|
|
function makes shift to left actually with the aid of function
|
|
`unsigned_integer_shift_left'. The function fixes overflow when
|
|
result can not be represented by number of given size, i.e. in
|
|
other words the opposite unsigned shift (to left) results in number
|
|
not equal to source operand. Result can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_shift_right(int size, const void *operand, int bits,
|
|
void *result) {
|
|
int byte_number;
|
|
unsigned byte;
|
|
unsigned carry;
|
|
int bit_shift;
|
|
int byte_shift;
|
|
|
|
if (bits < 0)
|
|
ammunition_unsigned_integer_shift_left(size, operand, -bits, result);
|
|
else {
|
|
ammunition_overflow_bit = 0;
|
|
byte_shift = bits / CHAR_BIT;
|
|
bit_shift = bits % CHAR_BIT;
|
|
__pragma_loopbound(0, 2);
|
|
for (byte_number = (byte_shift >= size ? 0 : size - byte_shift);
|
|
byte_number < size; byte_number++)
|
|
if (((unsigned char *) operand)[byte_number] != 0) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
if (byte_shift >= size)
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
else {
|
|
ammunition_memmove((char *) result + byte_shift, operand,
|
|
(size_t) (size - byte_shift));
|
|
ammunition_memset(result, 0, (size_t) byte_shift);
|
|
if (bit_shift == 0)
|
|
return;
|
|
__pragma_loopbound(3, 3);
|
|
for (byte_number = byte_shift, carry = 0; byte_number < size;
|
|
byte_number++) {
|
|
byte = ((unsigned char *) result)[byte_number];
|
|
((unsigned char *) result)[byte_number] =
|
|
carry | (byte >> bit_shift);
|
|
carry = (byte << (CHAR_BIT - bit_shift)) & UCHAR_MAX;
|
|
}
|
|
if (carry != 0)
|
|
ammunition_overflow_bit = 1;
|
|
}
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
}
|
|
|
|
/* This function makes right arithmetic shift of integer of given size
|
|
on given number of bits. If number of bits is negative the
|
|
function makes shift to left actually with the aid of function
|
|
`integer_shift_left'. The function fixes overflow when result can
|
|
not be represented by number of given size, i.e. in other words the
|
|
opposite shift (to left) results in number not equal to source
|
|
operand. Result can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_integer_shift_right(int size, const void *operand, int bits,
|
|
void *result) {
|
|
int byte_number;
|
|
unsigned byte;
|
|
unsigned carry;
|
|
int bit_shift;
|
|
int byte_shift;
|
|
int operand_sign;
|
|
|
|
if (bits < 0)
|
|
ammunition_integer_shift_left(size, operand, -bits, result);
|
|
else {
|
|
operand_sign = INTEGER_SIGN(operand);
|
|
ammunition_overflow_bit = 0;
|
|
byte_shift = bits / CHAR_BIT;
|
|
bit_shift = bits % CHAR_BIT;
|
|
__pragma_loopbound(0, 2);
|
|
for (byte_number = (byte_shift >= size ? 0 : size - byte_shift);
|
|
byte_number < size; byte_number++)
|
|
if (((unsigned char *) operand)[byte_number] != 0) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
if (byte_shift >= size)
|
|
ammunition_memset(result, (operand_sign ? UCHAR_MAX : 0),
|
|
(size_t) size);
|
|
else {
|
|
ammunition_memmove((char *) result + byte_shift, operand,
|
|
(size_t) (size - byte_shift));
|
|
ammunition_memset(result, (operand_sign ? UCHAR_MAX : 0),
|
|
(size_t) byte_shift);
|
|
if (bit_shift == 0)
|
|
return;
|
|
carry =
|
|
(((operand_sign ? UCHAR_MAX : 0) << (CHAR_BIT - bit_shift)) &
|
|
UCHAR_MAX);
|
|
__pragma_loopbound(3, 3);
|
|
for (byte_number = byte_shift; byte_number < size; byte_number++) {
|
|
byte = ((unsigned char *) result)[byte_number];
|
|
((unsigned char *) result)[byte_number] =
|
|
carry | (byte >> bit_shift);
|
|
carry = (byte << (CHAR_BIT - bit_shift)) & UCHAR_MAX;
|
|
}
|
|
if (carry != 0)
|
|
ammunition_overflow_bit = 1;
|
|
}
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
}
|
|
|
|
/* This function makes left shift of unsigned integer of given size on
|
|
given number of bits. If number of bits is negative the function
|
|
makes shift to left actually with the aid of function
|
|
`unsigned_integer_shift_right'. The function fixes overflow when
|
|
result can not be represented by number of given size, i.e. i.e. in
|
|
other words the opposite shift (to right) results in number not
|
|
equal to source operand. Result can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_shift_left(int size, const void *operand, int bits,
|
|
void *result) {
|
|
int byte_number;
|
|
unsigned byte;
|
|
unsigned carry;
|
|
int bit_shift;
|
|
int byte_shift;
|
|
|
|
if (bits < 0)
|
|
ammunition_unsigned_integer_shift_right(size, operand, -bits, result);
|
|
else {
|
|
ammunition_overflow_bit = 0;
|
|
byte_shift = bits / CHAR_BIT;
|
|
bit_shift = bits % CHAR_BIT;
|
|
__pragma_loopbound(0, 2);
|
|
for (byte_number = 0; byte_number < byte_shift && byte_number < size;
|
|
byte_number++)
|
|
if (((unsigned char *) operand)[byte_number] != 0) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
if (byte_shift >= size)
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
else {
|
|
ammunition_memmove(result, (char *) operand + byte_shift,
|
|
(size_t) (size - byte_shift));
|
|
ammunition_memset((char *) result + (size - byte_shift), 0,
|
|
(size_t) byte_shift);
|
|
if (bit_shift == 0)
|
|
return;
|
|
__pragma_loopbound(2, 3);
|
|
for (byte_number = size - byte_shift - 1, carry = 0;
|
|
byte_number >= 0; byte_number--) {
|
|
byte = ((unsigned char *) result)[byte_number];
|
|
((unsigned char *) result)[byte_number] =
|
|
carry | (byte << bit_shift);
|
|
carry = byte >> (CHAR_BIT - bit_shift);
|
|
}
|
|
if (carry != 0)
|
|
ammunition_overflow_bit = 1;
|
|
}
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
}
|
|
|
|
/* This function makes left arithmetic shift of integer of given size
|
|
on given number of bits. If number of bits is negative the
|
|
function makes shift to left actually with the aid of function
|
|
`integer_shift_right'. The function fixes overflow when result can
|
|
not be represented by number of given size, i.e. in other words the
|
|
opposite shift (to right) results in number not equal to source
|
|
operand. Result can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_integer_shift_left(int size, const void *operand, int bits,
|
|
void *result) {
|
|
int byte_number;
|
|
unsigned byte;
|
|
unsigned carry;
|
|
int bit_shift;
|
|
int byte_shift;
|
|
int operand_sign;
|
|
|
|
if (bits < 0)
|
|
ammunition_integer_shift_right(size, operand, -bits, result);
|
|
else {
|
|
operand_sign = INTEGER_SIGN(operand);
|
|
ammunition_overflow_bit = 0;
|
|
byte_shift = bits / CHAR_BIT;
|
|
bit_shift = bits % CHAR_BIT;
|
|
__pragma_loopbound(0, 2);
|
|
for (byte_number = 0; byte_number < byte_shift && byte_number < size;
|
|
byte_number++)
|
|
if (((unsigned char *) operand)[byte_number] !=
|
|
(operand_sign ? UCHAR_MAX : 0)) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
if (byte_shift >= size)
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
else {
|
|
ammunition_memmove(result, (char *) operand + byte_shift,
|
|
(size_t) (size - byte_shift));
|
|
ammunition_memset((char *) result + (size - byte_shift), 0,
|
|
(size_t) byte_shift);
|
|
if (bit_shift == 0)
|
|
return;
|
|
__pragma_loopbound(2, 3);
|
|
for (byte_number = size - byte_shift - 1, carry = 0;
|
|
byte_number >= 0; byte_number--) {
|
|
byte = ((unsigned char *) result)[byte_number];
|
|
((unsigned char *) result)[byte_number] =
|
|
carry | (byte << bit_shift);
|
|
carry = byte >> (CHAR_BIT - bit_shift);
|
|
}
|
|
if (carry != ((unsigned) (operand_sign ? UCHAR_MAX : 0) >>
|
|
(CHAR_BIT - bit_shift)))
|
|
ammunition_overflow_bit = 1;
|
|
}
|
|
if (operand_sign != INTEGER_SIGN(result))
|
|
ammunition_overflow_bit = 1;
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
}
|
|
|
|
/* This page contains functions for bitwise operations of arbitrary
|
|
precision numbers. */
|
|
|
|
/* This function makes bitwise `or' of two integers of given size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_integer_or(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int byte_number;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (byte_number = 0; byte_number < size; byte_number++) {
|
|
((unsigned char *) result)[byte_number] =
|
|
((unsigned char *) op1)[byte_number] |
|
|
((unsigned char *) op2)[byte_number];
|
|
}
|
|
}
|
|
|
|
/* This function makes bitwise `or' of two unsigned integers of given
|
|
size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_or(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_integer_or(size, op1, op2, result);
|
|
}
|
|
|
|
/* This function makes bitwise `and' of two integers of given size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_integer_and(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
int byte_number;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (byte_number = 0; byte_number < size; byte_number++) {
|
|
((unsigned char *) result)[byte_number] =
|
|
((unsigned char *) op1)[byte_number] &
|
|
((unsigned char *) op2)[byte_number];
|
|
}
|
|
}
|
|
|
|
/* This function makes bitwise `and' of two unsigned integers of given
|
|
size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_and(int size, const void *op1, const void *op2,
|
|
void *result) {
|
|
ammunition_integer_and(size, op1, op2, result);
|
|
}
|
|
|
|
/* This function makes bitwise `not' of integer of given size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_integer_not(int size, const void *operand, void *result) {
|
|
int byte_number;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (byte_number = 0; byte_number < size; byte_number++) {
|
|
((unsigned char *) result)[byte_number] =
|
|
((unsigned char *) operand)[byte_number] ^ UCHAR_MAX;
|
|
}
|
|
}
|
|
|
|
/* This function makes bitwise `not' of unsigned integer of given
|
|
size. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_unsigned_integer_not(int size, const void *operand, void *result) {
|
|
ammunition_integer_not(size, operand, result);
|
|
}
|
|
|
|
/* This page contains functions for comparison of arbitrary precision
|
|
numbers. */
|
|
|
|
/* This function compares two unsigned integers of given size on
|
|
equality. The function returns 1 if unsigned integers are equal, 0
|
|
otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_eq_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_memcmp(op1, op2, (size_t) size) == 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on equality. The
|
|
function returns 1 if integers are equal, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_eq_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_memcmp(op1, op2, (size_t) size) == 0;
|
|
}
|
|
|
|
/* This function compares two unsigned integers of given size on
|
|
inequality. The function returns 1 if unsigned integers are not
|
|
equal, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_ne_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_memcmp(op1, op2, (size_t) size) != 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on inequality.
|
|
The function returns 1 if integers are not equal, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_ne_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_memcmp(op1, op2, (size_t) size) != 0;
|
|
}
|
|
|
|
/* This function compares two memory parts of given size on that the
|
|
first operand is greater than the second. The bytes are described
|
|
as unsigned. The function returns 1 if the first operand is
|
|
greater than the second, - 1 if the first operand is less than the
|
|
second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_bytes_comparison(const void *op1, const void *op2, int size) {
|
|
const unsigned char *str1 = (unsigned const char *) op1;
|
|
const unsigned char *str2 = (unsigned const char *) op2;
|
|
|
|
__pragma_loopbound(1, 4);
|
|
while (size > 0 && *str1 == *str2) {
|
|
str1++;
|
|
str2++;
|
|
size--;
|
|
}
|
|
if (size <= 0)
|
|
return 0;
|
|
else if (*str1 > *str2)
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
/* This function compares two unsigned integers of given size on that
|
|
the first operand is greater than the second. The function returns
|
|
1 if the first unsigned integer is greater than the second, 0
|
|
otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_gt_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_bytes_comparison(op1, op2, size) > 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on that the first
|
|
operand is greater than the second. The function returns 1 if the
|
|
first integer is greater than the second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_gt_integer(int size, const void *op1, const void *op2) {
|
|
if (INTEGER_SIGN(op1) == 0) {
|
|
if (INTEGER_SIGN(op2) == 0)
|
|
return ammunition_bytes_comparison(op1, op2, size) > 0;
|
|
else
|
|
return 1; /* TRUE */
|
|
} else if (INTEGER_SIGN(op2) == 0)
|
|
return 0; /*FALSE*/
|
|
else
|
|
return ammunition_bytes_comparison(op1, op2, size) > 0;
|
|
}
|
|
|
|
/* This function compares two unsigned integers of given size on that
|
|
the first operand is less than the second. The function returns 1
|
|
if the first unsigned integer is less than the second, 0
|
|
otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_lt_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_bytes_comparison(op1, op2, size) < 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on that the first
|
|
operand is less than the second. The function returns 1 if the
|
|
first integer is less than the second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_lt_integer(int size, const void *op1, const void *op2) {
|
|
if (INTEGER_SIGN(op1) == 0) {
|
|
if (INTEGER_SIGN(op2) == 0)
|
|
return ammunition_bytes_comparison(op1, op2, size) < 0;
|
|
else
|
|
return 0; /*FALSE*/
|
|
} else if (INTEGER_SIGN(op2) == 0)
|
|
return 1; /* TRUE */
|
|
else
|
|
return ammunition_bytes_comparison(op1, op2, size) < 0;
|
|
}
|
|
|
|
/* This function compares two unsigned integers of given size on that
|
|
the first operand is greater than or equal to the second. The
|
|
function returns 1 if the first unsigned integer is greater than or
|
|
equal to the second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_ge_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_bytes_comparison(op1, op2, size) >= 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on that the first
|
|
operand is greater than or equal to the second. The function
|
|
returns 1 if the first integer is greater than or equal to the
|
|
second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_ge_integer(int size, const void *op1, const void *op2) {
|
|
if (INTEGER_SIGN(op1) == 0) {
|
|
if (INTEGER_SIGN(op2) == 0)
|
|
return ammunition_bytes_comparison(op1, op2, size) >= 0;
|
|
else
|
|
return 1; /* TRUE */
|
|
} else if (INTEGER_SIGN(op2) == 0)
|
|
return 0; /*FALSE*/
|
|
else
|
|
return ammunition_bytes_comparison(op1, op2, size) >= 0;
|
|
}
|
|
|
|
/* This function compares two unsigned integers of given size on that
|
|
the first operand is less than or equal to the second. The
|
|
function returns 1 if the first unsigned integer is less than or
|
|
equal to the second, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_le_unsigned_integer(int size, const void *op1, const void *op2) {
|
|
return ammunition_bytes_comparison(op1, op2, size) <= 0;
|
|
}
|
|
|
|
/* This function compares two integers of given size on that the first
|
|
operand is less than or equal to the second. The function returns
|
|
1 if the first integer is less than or equal to the second, 0
|
|
otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_le_integer(int size, const void *op1, const void *op2) {
|
|
if (INTEGER_SIGN(op1) == 0) {
|
|
if (INTEGER_SIGN(op2) == 0)
|
|
return ammunition_bytes_comparison(op1, op2, size) <= 0;
|
|
else
|
|
return 0; /*FALSE*/
|
|
} else if (INTEGER_SIGN(op2) == 0)
|
|
return 1; /* TRUE */
|
|
else
|
|
return ammunition_bytes_comparison(op1, op2, size) <= 0;
|
|
}
|
|
|
|
/* This page contains functions for changing size of arbitrary
|
|
precision numbers. */
|
|
|
|
/* The function changes size of unsigned integer. The function fixes
|
|
overflow when result can not be represented by number of given
|
|
size. Result can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_change_unsigned_integer_size(int operand_size, const void *operand,
|
|
int result_size, void *result) {
|
|
int operand_digit_number;
|
|
|
|
ammunition_overflow_bit = 0;
|
|
if (operand_size <= result_size) {
|
|
ammunition_memmove((char *) result + result_size - operand_size,
|
|
operand, (size_t) operand_size);
|
|
ammunition_memset(result, 0, (size_t) (result_size - operand_size));
|
|
} else {
|
|
__pragma_loopbound(1, 2);
|
|
for (operand_digit_number = 0;
|
|
operand_digit_number < operand_size - result_size;
|
|
operand_digit_number++) {
|
|
if (((unsigned char *) operand)[operand_digit_number] != 0) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
}
|
|
ammunition_memmove(result,
|
|
(char *) operand + operand_size - result_size,
|
|
(size_t) result_size);
|
|
}
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
}
|
|
|
|
/* The function changes size of integer. The function fixes overflow
|
|
when result can not be represented by number of given size. Result
|
|
can be placed in operand. */
|
|
|
|
__attribute__((always_inline)) static inline void
|
|
ammunition_change_integer_size(int operand_size, const void *operand,
|
|
int result_size, void *result) {
|
|
int operand_digit_number;
|
|
int operand_sign;
|
|
|
|
ammunition_overflow_bit = 0;
|
|
operand_sign = INTEGER_SIGN(operand);
|
|
if (operand_size <= result_size) {
|
|
ammunition_memmove((char *) result + result_size - operand_size,
|
|
operand, (size_t) operand_size);
|
|
ammunition_memset(result, (operand_sign ? UCHAR_MAX : 0),
|
|
(size_t) (result_size - operand_size));
|
|
} else {
|
|
__pragma_loopbound(2, 2);
|
|
for (operand_digit_number = 0;
|
|
operand_digit_number < operand_size - result_size;
|
|
operand_digit_number++) {
|
|
if (((unsigned char *) operand)[operand_digit_number] !=
|
|
(operand_sign ? UCHAR_MAX : 0)) {
|
|
ammunition_overflow_bit = 1;
|
|
break;
|
|
}
|
|
}
|
|
ammunition_memmove(result,
|
|
(char *) operand + operand_size - result_size,
|
|
(size_t) result_size);
|
|
if (operand_sign != INTEGER_SIGN(result))
|
|
ammunition_overflow_bit = 1;
|
|
}
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_overflow_reaction();
|
|
}
|
|
|
|
/* This page contains functions for conversion of arbitrary precision
|
|
numbers to ascii representation. */
|
|
|
|
/* This function transforms unsigned integer of given size to BASE
|
|
ascii representation. BASE should be between 2 and 36 including
|
|
them. Digits more 9 are represented by 'a', 'b' etc. Sign is
|
|
absent in result string. The function returns the result
|
|
string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_unsigned_integer_to_based_string(int size, const void *operand,
|
|
int base, char *result) {
|
|
int digit_num;
|
|
int i;
|
|
unsigned long long divisable;
|
|
unsigned long long remainder;
|
|
int nonzero_flag;
|
|
int length;
|
|
int temporary;
|
|
unsigned char operand_copy[MAX_INTEGER_OPERAND_SIZE];
|
|
|
|
ammunition_memcpy(operand_copy, operand, (size_t) size);
|
|
length = 0;
|
|
__pragma_loopbound(1, 10);
|
|
do {
|
|
nonzero_flag = 0 /* FALSE */;
|
|
__pragma_loopbound(2, 6);
|
|
for (digit_num = 0, remainder = 0; digit_num < size; digit_num++) {
|
|
divisable = remainder * (UCHAR_MAX + 1) + operand_copy[digit_num];
|
|
remainder = divisable % base;
|
|
operand_copy[digit_num] = (unsigned char) (divisable / base);
|
|
if (operand_copy[digit_num] != 0)
|
|
nonzero_flag = 1 /* TRUE */;
|
|
}
|
|
result[length++] =
|
|
(unsigned char) (remainder < 10 ? '0' + remainder
|
|
: 'a' + remainder - 10);
|
|
} while (nonzero_flag);
|
|
result[length] = '\0';
|
|
__pragma_loopbound(0, 5);
|
|
for (i = 0; i < length / 2; i++) {
|
|
temporary = result[i];
|
|
result[i] = result[length - i - 1];
|
|
result[length - i - 1] = temporary;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* This function transforms unsigned integer of given size to decimal
|
|
ascii representation. Sign is absent in result string. The
|
|
function returns the result string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_unsigned_integer_to_string(int size, const void *operand,
|
|
char *result) {
|
|
return ammunition_unsigned_integer_to_based_string(size, operand, 10,
|
|
result);
|
|
}
|
|
|
|
/* This function transforms integer of given size to BASE ascii
|
|
representation. BASE should be between 2 and 36 including them.
|
|
Digits more 9 are represented by 'a', 'b' etc. Sign is present in
|
|
result string only for negative numbers. The function returns the
|
|
result string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_integer_to_based_string(int size, const void *operand, int base,
|
|
char *result) {
|
|
unsigned char operand_copy[MAX_INTEGER_OPERAND_SIZE];
|
|
|
|
if (!INTEGER_SIGN(operand))
|
|
return ammunition_unsigned_integer_to_based_string(size, operand, base,
|
|
result);
|
|
ammunition_memcpy(operand_copy, operand, (size_t) size);
|
|
/* May be integer overflow. But result is correct because it is unsigned. */
|
|
ammunition_make_complementary_code(size, operand_copy, operand_copy);
|
|
*result = '-';
|
|
ammunition_unsigned_integer_to_based_string(size, operand_copy, base,
|
|
result + 1);
|
|
return result;
|
|
}
|
|
|
|
/* This function transforms integer of given size to decimal ascii
|
|
representation. Sign is present in result string only for negative
|
|
numbers. The function returns the result string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_integer_to_string(int size, const void *operand, char *result) {
|
|
return ammunition_integer_to_based_string(size, operand, 10, result);
|
|
}
|
|
|
|
/* This page contains functions for conversion of decimal ascii
|
|
representation to arbitrary precision numbers. */
|
|
|
|
/* The function adds digit (byte size) to unsigned integer. The
|
|
function returns 1 if unsigned integer overflow is fixed, 0
|
|
otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_add_digit_to_unsigned_integer_without_overflow_reaction(
|
|
int size, void *operand, unsigned int digit) {
|
|
int digit_num;
|
|
unsigned int carry;
|
|
unsigned int sum;
|
|
|
|
__pragma_loopbound(4, 4);
|
|
for (digit_num = size - 1, carry = digit; digit_num >= 0; digit_num--) {
|
|
sum = ((unsigned char *) operand)[digit_num] + carry;
|
|
if (sum > UCHAR_MAX) {
|
|
carry = sum / (UCHAR_MAX + 1);
|
|
sum %= UCHAR_MAX + 1;
|
|
} else
|
|
carry = 0;
|
|
((unsigned char *) operand)[digit_num] = sum;
|
|
}
|
|
return carry != 0;
|
|
}
|
|
|
|
/* This function transforms source string (decimal ascii
|
|
representation without sign) to given size unsigned integer and
|
|
returns pointer to first non digit in the source string through a
|
|
parameter. If the string started with invalid integer
|
|
representation the result will be zero and returns the operand
|
|
through the parameter. The function returns 1 if unsigned integer
|
|
overflow is fixed, 0 otherwise. */
|
|
|
|
__attribute__((always_inline)) static inline int
|
|
ammunition_string_to_unsigned_integer_without_overflow_reaction(
|
|
int size, const char *operand, void *result, char **first_nondigit) {
|
|
int overflow_flag;
|
|
|
|
ammunition_memset(result, 0, (size_t) size);
|
|
__pragma_loopbound(1, 10);
|
|
for (overflow_flag = 0; ammunition_isdigit(*operand); operand++) {
|
|
overflow_flag =
|
|
overflow_flag ||
|
|
ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction(
|
|
size, result, 10);
|
|
overflow_flag =
|
|
overflow_flag ||
|
|
ammunition_add_digit_to_unsigned_integer_without_overflow_reaction(
|
|
size, result, *operand - '0');
|
|
}
|
|
*first_nondigit = (char *) operand;
|
|
return overflow_flag;
|
|
}
|
|
|
|
/* This function skips all white spaces at the begin of source string
|
|
and transforms tail of the source string (decimal ascii
|
|
representation without sign) to given size unsigned integer with
|
|
the aid of function
|
|
`string_to_unsigned_integer_without_overflow_reaction'. If the
|
|
string started with invalid unsigned integer representation the
|
|
result will be zero. The function fixes overflow when result can
|
|
not be represented by number of given size. The function returns
|
|
address of the first nondigit in the source string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_unsigned_integer_from_string(int size, const char *operand,
|
|
void *result) {
|
|
char *first_nondigit;
|
|
|
|
__pragma_loopbound(0, 0);
|
|
while (ammunition_isspace(*operand))
|
|
operand++;
|
|
ammunition_overflow_bit =
|
|
ammunition_string_to_unsigned_integer_without_overflow_reaction(
|
|
size, operand, result, &first_nondigit);
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
return first_nondigit;
|
|
}
|
|
|
|
/* This function skips all white spaces at the begin of source string
|
|
and transforms tail of the source string (decimal ascii
|
|
representation with possible sign `+' or `-') to given size integer
|
|
with the aid of function
|
|
`string_to_unsigned_integer_without_overflow_reaction'. If the
|
|
string started with invalid integer representation the result will
|
|
be zero. The function fixes overflow when result can not be
|
|
represented by number of given size. the function returns Address
|
|
of the first nondigit in the source string. */
|
|
|
|
__attribute__((always_inline)) static inline char *
|
|
ammunition_integer_from_string(int size, const char *operand, void *result) {
|
|
int negative_number_flag;
|
|
char *first_nondigit;
|
|
int unsigned_result_sign;
|
|
|
|
__pragma_loopbound(0, 0);
|
|
while (ammunition_isspace(*operand))
|
|
operand++;
|
|
negative_number_flag = 0; /* FALSE */
|
|
if (*operand == '+')
|
|
operand++;
|
|
else if (*operand == '-') {
|
|
operand++;
|
|
negative_number_flag = 1; /* TRUE */
|
|
}
|
|
ammunition_overflow_bit =
|
|
ammunition_string_to_unsigned_integer_without_overflow_reaction(
|
|
size, operand, result, &first_nondigit);
|
|
unsigned_result_sign = INTEGER_SIGN(result);
|
|
if (negative_number_flag)
|
|
/* May be integer overflow when `result' is correct. But result
|
|
is correct because it is unsigned. */
|
|
ammunition_make_complementary_code(size, result, result);
|
|
ammunition_overflow_bit = ammunition_overflow_bit ||
|
|
(unsigned_result_sign &&
|
|
(!negative_number_flag ||
|
|
INTEGER_SIGN(result) != unsigned_result_sign));
|
|
if (ammunition_overflow_bit)
|
|
ammunition_arithmetic_unsigned_overflow_reaction();
|
|
return first_nondigit;
|
|
}
|