#include <limits.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#define bitsof(T) (CHAR_BIT * sizeof(T))
typedef unsigned int mcc_test_t;
#define MCC_TEST_END_BIT (~(UINT_MAX >> 1))
#define MCC_TEST_PRI_PFX ""
#define INC_BITMATH
#define MCC__INT_USE_HUGE
#ifndef MCC__INT_USE_HUGE
//#define MCC__INT_USE_TEST
#define MCC__INT_USE_CHAR
#endif
#ifdef MCC__INT_USE_TEST
typedef mcc_test_t mcc_int_seg_t;
#define MCC__INT_SEG_END_BIT MCC_TEST_END_BIT
#define MCC__INT_SEG_PRI_PFX MCC_TEST_PRI_PFX
#elif defined( MCC__INT_USE_CHAR )
typedef unsigned char mcc_int_seg_t;
#define MCC__INT_SEG_END_BIT (~(UCHAR_MAX >> 1))
#define MCC__INT_SEG_PRI_PFX ""
#elif defined( MCC__INT_USE_HUGE )
typedef unsigned __int128 mcc_int_seg_t;
#define MCC__INT_SEG_END_BIT (~((~((unsigned __int128)0u)) >> 1))
#define MCC__INT_SEG_PRI_PFX "I128"
#else
typedef unsigned long mcc_int_seg_t;
#define MCC__INT_SEG_END_BIT (~(ULONG_MAX >> 1))
#define MCC__INT_SEG_PRI_PFX "l"
#endif
typedef struct mcc_bit
{
mcc_int_seg_t i;
mcc_int_seg_t *seg;
mcc_int_seg_t b;
mcc_int_seg_t bit;
} mcc_bit_t;
mcc_bit_t
mcc_bit_op_inc (mcc_bit_t num)
{
mcc_int_seg_t max = 0;
max = ~max;
if (num.b == max)
{
memset (&num, 0, sizeof (num));
return num;
}
++(num.b);
num.bit <<= 1;
if (!(num.bit))
{
num.bit = 1;
++(num.i);
++(num.seg);
}
return num;
}
mcc_bit_t
mcc_bit_op_dec (mcc_bit_t num)
{
if (!num.b)
{
memset (&num, 0, sizeof (num));
return num;
}
--(num.b);
num.bit >>= 1;
if (!(num.bit))
{
num.bit = MCC__INT_SEG_END_BIT;
--(num.i);
--(num.seg);
}
return num;
}
mcc_bit_t
mcc_bit_op_dec_for_bit (mcc_bit_t stop, mcc_bit_t zero)
{
while (stop.b > zero.b)
{
stop = mcc_bit_op_dec (stop);
if (*(stop.seg) & stop.bit)
return stop;
}
return stop;
}
#define MCC_BIT_SLOW
mcc_bit_t
mcc__bit_op_add (mcc_bit_t num, mcc_int_seg_t bits)
{
#ifdef MCC_BIT_SLOW
while (bits--)
{
num = mcc_bit_op_inc (num);
if (!(num.bit))
return num;
}
return num;
#else
mcc_int_seg_t i = num.bit;
if (i == 1u)
goto mcc__bit_op_add_bytes;
while (bits && i)
{
--bits;
i <<= 1u;
num = mcc_bit_op_inc (num);
if (!(num.bit))
return num;
}
mcc__bit_op_add_bytes:
if (!bits)
return num;
i = num.b;
num.b += bits;
if (num.b < i)
{
memset (&num, 0, sizeof (num));
return num;
}
i = bits / bitsof (i);
num.i += i;
num.seg += i;
num.bit = 1u << (bits %= bitsof (i));
return num;
#endif
}
mcc_bit_t
mcc__bit_op_sub (mcc_bit_t num, mcc_int_seg_t bits)
{
#ifdef MCC_BIT_SLOW
while (bits--)
{
num = mcc_bit_op_dec (num);
if (!(num.bit))
return num;
}
return num;
#else
mcc_int_seg_t i = num.bit;
if (i == MCC__INT_SEG_END_BIT)
goto mcc__bit_op_sub_bytes;
while (bits && i)
{
--bits;
i >>= 1;
num = mcc_bit_op_dec (num);
if (!(num.bit))
return num;
}
mcc__bit_op_sub_bytes:
if (!bits)
return num;
i = num.b;
num.b -= bits;
if (num.b > i)
{
memset (&num, 0, sizeof (num));
return num;
}
i = bits / bitsof (i);
num.i -= i;
num.seg -= i;
num.bit >>= (bits % bitsof (i));
return num;
#endif
}
int
mcc_bit_op_cmp (mcc_bit_t num, mcc_bit_t val)
{
if (num.b > val.b)
return 1;
if (num.b < val.b)
return -1;
return 0;
}
#ifndef INC_BITMATH
int test (mcc_test_t num, char *op, mcc_test_t val);
char *operations[] = {
"==", "!=", "!", ">", ">=", "<", "<=",
"<<", ">>", "|", "&", "^",
"+", "*", "-", "/", "%",
NULL
};
typedef time_t mcc_rnd_t;
long
mcc__rnd (mcc_rnd_t * ctx, long min, long max)
{
/* With bit unitialised it should be much harder to predict
* if 1 or 0 will be recieved */
mcc_rnd_t bit = 1, seed = time (NULL), mov = 0;
long val;
if (ctx)
mov = *ctx;
bit <<= mov++;
if (!bit || bit > seed)
{
bit = 1;
mov = 0;
}
val = (seed & bit) ? 1 : 0;
bit <<= 1;
if (ctx)
*ctx = mov;
if (min > max)
min = max;
if (min != max)
{
seed *= clock ();
bit = ~((~0u) << mov);
val = (seed & bit);
if (val > max)
val = max;
val -= (min >= 0) ? min : -min;
return (val < min) ? min : val;
}
return val ? max : min;
}
#define mcc_rnd( ctx ) mcc__rnd( ctx, LONG_MIN, LONG_MAX )
int
main ()
{
mcc_test_t i, j;
mcc_rnd_t ctx;
for (j = 0; j < 10; ++j)
{
for (i = 0; operations[i]; ++i)
{
test (mcc_rnd (&ctx), operations[i], mcc_rnd (&ctx));
}
}
return 0;
}
#endif
typedef struct mcc__int
{
int exit;
size_t size;
/* Tells shallow functions to free memory before exit */
_Bool temp;
mcc_bit_t zero, stop;
} mcc__int_t, mcc_int_t, mcc_uint_t;
int
mcc_int_validate (mcc__int_t const *const num)
{
if (!num || !(num->zero.seg) || !(num->stop.seg))
return EADDRNOTAVAIL;
if (mcc_bit_op_cmp (num->zero, num->stop) > 0)
return ERANGE;
return EXIT_SUCCESS;
}
int
mcc_int_validate2 (mcc__int_t const *const num, mcc__int_t const *const val)
{
int ret = mcc_int_validate (num);
switch (ret)
{
case EXIT_SUCCESS:
break;
case EADDRNOTAVAIL:
return EDESTADDRREQ;
default:
return ret;
}
return mcc_int_validate (val);
}
int
mcc_int_validate3 (mcc__int_t const *const num, mcc__int_t const *const val,
mcc__int_t const *const var)
{
int ret = mcc_int_validate2 (num, val);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_validate (var);
if (ret != EXIT_SUCCESS)
return (ret == EADDRNOTAVAIL) ? EDESTADDRREQ : ret;
if (var->size < num->size)
return ERANGE;
return EXIT_SUCCESS;
}
void
mcc_int_print (mcc__int_t num, mcc_int_seg_t min)
{
int ret = mcc_int_validate (&num);
mcc_int_seg_t nb;
if (ret != EXIT_SUCCESS)
return;
nb = num.stop.b - num.zero.b;
while (min-- > nb)
putchar ('0');
while (nb--)
{
num.stop = mcc_bit_op_dec (num.stop);
putchar ('0' + ! !(*(num.stop.seg) & num.stop.bit));
}
}
int
mcc_int_wrap (mcc__int_t * dst, mcc_int_seg_t * src, size_t count)
{
if (!dst)
return EDESTADDRREQ;
if (!src)
return EADDRNOTAVAIL;
if (!count)
return ERANGE;
(void) memset (dst, 0, sizeof (mcc__int_t));
dst->size = count * sizeof (mcc_int_seg_t);
dst->zero.seg = src;
dst->zero.bit = 1;
dst->stop = mcc__bit_op_add (dst->zero, dst->size * CHAR_BIT);
return EXIT_SUCCESS;
}
int
mcc_int_size (mcc__int_t * dst, size_t size)
{
mcc_int_seg_t *mem;
size_t nodes;
if (!size)
{
if (dst->zero.seg)
free (dst->zero.seg);
memset (dst, 0, sizeof (mcc_int_seg_t));
return EXIT_SUCCESS;
}
nodes = size / sizeof (mcc_int_seg_t);
if (size % sizeof (mcc_int_seg_t))
++nodes;
size = nodes * sizeof (mcc_int_seg_t);
if (!(dst->zero.seg))
mem = malloc (size);
else
mem = realloc (dst->zero.seg, size);
if (!mem)
ENOMEM;
(void) memset (&(dst->zero), 0, sizeof (mcc_bit_t));
dst->zero.seg = mem;
dst->zero.bit = 1;
dst->size = size;
dst->stop = mcc__bit_op_add (dst->zero, size * CHAR_BIT);
return EXIT_SUCCESS;
}
int
mcc_int_size_and_fill (mcc__int_t * dst, void const *src, size_t size)
{
int ret = mcc_int_size (dst, size);
if (ret != EXIT_SUCCESS)
return ret;
(void) memset (dst->zero.seg, 0, dst->size);
(void) memcpy (dst->zero.seg, src, size);
return EXIT_SUCCESS;
}
int
mcc__int_op_cmp (mcc__int_t const *const num, mcc__int_t const *const val)
{
mcc_bit_t n = { 0 }, v =
{
0};
mcc_int_seg_t nb = 0, vb = 0;
int nn0 = 0, vn0 = 0;
if (mcc_int_validate (num) == EXIT_SUCCESS)
{
n = mcc_bit_op_dec_for_bit (num->stop, num->zero);
nn0 = (*(n.seg) & n.bit) ? 1 : 0;
nb = n.b - num->zero.b;
}
if (mcc_int_validate (val) == EXIT_SUCCESS)
{
v = mcc_bit_op_dec_for_bit (val->stop, val->zero);
vn0 = (*(v.seg) & v.bit) ? 1 : 0;
vb = v.b - val->zero.b;
}
if (!(n.bit))
return -vn0;
if (!(v.bit))
return nn0;
if (nb != vb)
return (nb > vb) ? 1 : -1;
while (nb)
{
if (nb)
{
n = mcc_bit_op_dec_for_bit (n, num->zero);
nb = n.b - num->zero.b;
}
if (vb)
{
v = mcc_bit_op_dec_for_bit (v, val->zero);
vb = v.b - val->zero.b;
}
if (nb != vb)
return (nb > vb) ? 1 : -1;
}
nb = (*(n.seg) & n.bit) ? 1 : 0;
vb = (*(v.seg) & v.bit) ? 1 : 0;
if (nb != vb)
return (nb > vb) ? 1 : -1;
return 0;
}
#define mcc__int_is_nil( num ) (mcc__int_op_cmp( num, NULL ) == 0)
#define mcc__int_is_eql( num, val ) (mcc__int_op_cmp( num, val ) == 0)
#define mcc__int_is_neq( num, val ) (mcc__int_op_cmp( num, val ) != 0)
#define mcc__int_is_gth( num, val ) (mcc__int_op_cmp( num, val ) > 0)
#define mcc__int_is_gte( num, val ) (mcc__int_op_cmp( num, val ) >= 0)
#define mcc__int_is_lth( num, val ) (mcc__int_op_cmp( num, val ) < 0)
#define mcc__int_is_lte( num, val ) (mcc__int_op_cmp( num, val ) <= 0)
int
biclamp1 (mcc__int_t * num)
{
int ret = mcc_int_validate (num);
mcc_bit_t one, pos;
if (ret != EXIT_SUCCESS)
return ret;
one = mcc_bit_op_dec (pos = num->stop);
while (pos.i == one.i)
{
if (!(*(pos.seg) & pos.bit))
*(pos.seg) |= pos.bit;
}
return EXIT_SUCCESS;
}
int
biclamp0 (mcc__int_t * num)
{
int ret = mcc_int_validate (num);
mcc_bit_t one, pos;
if (ret != EXIT_SUCCESS)
return ret;
one = mcc_bit_op_dec (pos = num->stop);
while (pos.i == one.i)
{
if (*(pos.seg) & pos.bit)
*(pos.seg) ^= pos.bit;
}
return EXIT_SUCCESS;
}
int
mcc__int_op_aor (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc_bit_t n, v, e;
if (ret != EXIT_SUCCESS)
return ret;
n = num->zero;
v = val->zero;
e = (mcc_bit_op_cmp (num->stop, val->stop) < 0) ? num->stop : val->stop;
while (n.b < e.b && v.b < e.b)
{
if (*(v.seg) & v.bit)
*(n.seg) |= n.bit;
n = mcc_bit_op_inc (n);
v = mcc_bit_op_inc (v);
}
return EXIT_SUCCESS;
}
int
mcc__int_op_xor (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc_bit_t n, v, e;
if (ret != EXIT_SUCCESS)
return ret;
n = num->zero;
v = val->zero;
e = (mcc_bit_op_cmp (num->stop, val->stop) < 0) ? num->stop : val->stop;
while (n.b < e.b && v.b < e.b)
{
if (*(v.seg) & v.bit)
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc (n);
v = mcc_bit_op_inc (v);
}
return EXIT_SUCCESS;
}
int
mcc__int_op_and (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc_bit_t n, v, e;
if (ret != EXIT_SUCCESS)
return ret;
n = num->zero;
v = val->zero;
e = (mcc_bit_op_cmp (num->stop, val->stop) < 0) ? num->stop : val->stop;
while (n.b < e.b && v.b < e.b)
{
if (!(*(v.seg) & v.bit) && *(n.seg) & n.bit)
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc (n);
v = mcc_bit_op_inc (v);
}
while (n.b < num->stop.b)
{
if (*(n.seg) & n.bit)
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc (n);
}
return EXIT_SUCCESS;
}
int
mcc___int_op_shl (mcc__int_t * num, mcc_int_seg_t bits)
{
int ret = mcc_int_validate (num);
mcc_bit_t n, v;
mcc_int_seg_t max_bits;
if (ret != EXIT_SUCCESS)
return ret;
max_bits = (num->stop.b - num->zero.b);
if (bits >= max_bits)
bits %= max_bits;
if (!bits)
return EXIT_SUCCESS;
n = num->stop;
v = mcc__bit_op_sub (n, bits);
while (v.b > num->zero.b)
{
n = mcc_bit_op_dec (n);
v = mcc_bit_op_dec (v);
if (*(v.seg) & v.bit)
*(n.seg) |= n.bit;
else if (*(n.seg) & n.bit)
*(n.seg) ^= n.bit;
}
while (n.b)
{
n = mcc_bit_op_dec (n);
if (*(n.seg) & n.bit)
*(n.seg) ^= n.bit;
}
return EXIT_SUCCESS;
}
int
mcc___int_op_shr (mcc__int_t * num, mcc_int_seg_t bits)
{
int ret = mcc_int_validate (num);
mcc_bit_t n, v;
mcc_int_seg_t max_bits;
if (ret != EXIT_SUCCESS)
return ret;
max_bits = (num->stop.b - num->zero.b);
if (bits >= max_bits)
bits %= max_bits;
if (!bits)
return EXIT_SUCCESS;
n = num->zero;
v = mcc__bit_op_add (n, bits);
while (v.b < num->stop.b)
{
if (*(v.seg) & v.bit)
*(n.seg) |= n.bit;
else if (*(n.seg) & n.bit)
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc (n);
v = mcc_bit_op_inc (v);
}
while (n.bit > 1u)
{
if (*(n.seg) & n.bit)
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc (n);
}
if (n.i < num->stop.i)
{
n.i = num->stop.i - n.i;
memset (n.seg, 0, n.i * sizeof (mcc_int_seg_t));
}
return EXIT_SUCCESS;
}
int
mcc__int_op_add (mcc__int_t * num, mcc__int_t const *const val)
{
mcc_bit_t n, v, stop;
mcc_int_seg_t b = 0, bits, nb, vb;
_Bool c = 0;
int ret = mcc_int_validate2 (num, val);
if (ret != EXIT_SUCCESS)
return ret;
n = num->zero;
v = val->zero;
nb = num->stop.b - num->zero.b;
vb = val->stop.b - val->zero.b;
bits = (nb < vb) ? nb : vb;
stop = (mcc_bit_op_cmp (num->stop, val->stop) < 0) ? num->stop : val->stop;
for (; b < bits; ++b)
{
if (c)
{
*(n.seg) ^= n.bit;
if (*(n.seg) & n.bit)
c = 0;
}
if (*(v.seg) & v.bit)
{
*(n.seg) ^= n.bit;
if (!(*(n.seg) & n.bit))
c = 1;
}
n = mcc_bit_op_inc (n);
v = mcc_bit_op_inc (v);
}
if (c)
{
for (; n.b < stop.b; n = mcc_bit_op_inc (n))
{
*(n.seg) ^= n.bit;
if (*(n.seg) & n.bit)
{
c = 0;
break;
}
}
}
return c ? EOVERFLOW : EXIT_SUCCESS;
}
int
add_uint (mcc__int_t * num, mcc__int_t * val)
{
int ret = mcc__int_op_add (num, val);
if (ret == EOVERFLOW)
{
memset (num->zero.seg, -1, num->size);
ret = biclamp0 (num);
}
return ret;
}
int
add_int (mcc__int_t * num, mcc__int_t * val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t tmp;
if (ret != EXIT_SUCCESS)
return ret;
tmp = *num;
tmp.stop = mcc_bit_op_dec (tmp.stop);
ret = mcc__int_op_add (&tmp, val);
if (ret == EOVERFLOW)
{
memset (num->zero.seg, -1, num->size);
ret = biclamp0 (&tmp);
}
return ret;
}
int
mcc__int_op_sub (mcc__int_t * num, mcc__int_t const *const val)
{
mcc_bit_t n, v, s;
_Bool c = 0;
mcc_int_seg_t b = 0, bits = 0, nb, vb;
int ret = mcc_int_validate2 (num, val);
if (ret != EXIT_SUCCESS)
return ret;
n = num->zero;
v = val->zero;
s = val->stop;
//s = mcc_bit_op_inc(mcc_bit_op_dec_for_bit(s, val->zero));
nb = num->stop.b - num->zero.b;
vb = s.b - val->zero.b;
bits = (nb < vb) ? nb : vb;
for (; b < bits; ++b, n = mcc_bit_op_inc (n), v = mcc_bit_op_inc (v))
{
if (c)
{
if (*(n.seg) & n.bit)
c = 0;
*(n.seg) ^= n.bit;
}
if (*(v.seg) & v.bit)
{
*(n.seg) ^= n.bit;
if (*(n.seg) & n.bit)
c = 1;
}
}
if (c)
{
for (; b < nb; ++b, n = mcc_bit_op_inc (n))
{
*(n.seg) ^= n.bit;
if (!(*(n.seg) & n.bit))
{
c = 0;
break;
}
}
}
return c ? EOVERFLOW : EXIT_SUCCESS;
}
int
mcc___int_op_mul (mcc__int_t * num, mcc__int_t const *const val,
mcc__int_t * tmp)
{
int ret = mcc_int_validate3 (num, val, tmp);
mcc_bit_t v, s;
mcc_int_seg_t bits = 0;
if (ret != EXIT_SUCCESS)
return ret;
s = mcc_bit_op_inc (mcc_bit_op_dec_for_bit (val->stop, val->zero));
memset (tmp->zero.seg, 0, tmp->size);
memcpy (tmp->zero.seg, num->zero.seg, num->size);
memset (num->zero.seg, 0, num->size);
for (v = val->zero; v.b < s.b; v = mcc_bit_op_inc (v))
{
if (*(v.seg) & v.bit)
{
(void) mcc___int_op_shl (tmp, bits);
if (mcc__int_op_add (num, tmp) == EOVERFLOW)
ret = EOVERFLOW;
bits = 0;
}
++bits;
}
return ret;
}
int
mcc__int_op_mul (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t tmp = { 0 };
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_size_and_fill (&tmp, num->zero.seg, num->size);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc___int_op_mul (num, val, &tmp);
(void) mcc_int_size (&tmp, 0);
return ret;
}
int
mcc___int_op_div (mcc__int_t * num, mcc__int_t const *const val,
mcc__int_t * rem)
{
int ret = mcc_int_validate3 (num, val, rem);
mcc__int_t seg = { 0 }, tmp =
{
0};
mcc_bit_t quo;
if (ret != EXIT_SUCCESS)
return ret;
(void) memset (rem->zero.seg, 0, rem->size);
(void) memcpy (rem->zero.seg, num->zero.seg, num->size);
(void) memset (num->zero.seg, 0, num->size);
#if 1
if (mcc__int_is_nil (val))
return EXIT_SUCCESS;
#else
if (mcc__int_is_nil (val))
{
assert (!mcc__int_is_nil (val));
return EXIT_SUCCESS;
}
#endif
tmp = *val;
tmp.stop = mcc_bit_op_inc (mcc_bit_op_dec_for_bit (tmp.stop, tmp.zero));
seg = *rem;
seg.zero = seg.stop;
quo = num->stop;
while (mcc__int_is_gte (rem, &tmp))
{
seg.zero = mcc_bit_op_dec (seg.zero);
quo = mcc_bit_op_dec (quo);
if (mcc__int_is_gte (&seg, &tmp))
{
if (mcc__int_op_sub (&seg, &tmp) == EOVERFLOW)
ret = EOVERFLOW;
*(quo.seg) |= quo.bit;
}
}
return ret;
}
int
mcc__int_op_div (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t rem = { 0 };
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_size (&rem, num->size);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc___int_op_div (num, val, &rem);
(void) mcc_int_size (&rem, 0);
return ret;
}
int
mcc__int_op_mod (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t rem = { 0 };
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_size (&rem, num->size);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc___int_op_div (num, val, &rem);
(void) memcpy (num->zero.seg, rem.zero.seg, num->size);
(void) mcc_int_size (&rem, 0);
return ret;
}
int
mcc__int_op_shl (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t tmp = { 0 }, cpy =
{
0}, rem =
{
0};
mcc_int_seg_t move = 0, bits = 0;
if (ret != EXIT_SUCCESS)
return ret;
bits = num->stop.b - num->zero.b;
ret = mcc_int_wrap (&tmp, &bits, 1);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_wrap (&rem, &move, 1);
if (ret != EXIT_SUCCESS)
return ret;
move = *(val->zero.seg);
if (mcc__int_is_gte (val, &tmp))
{
ret = mcc_int_size_and_fill (&cpy, val->zero.seg, val->size);
if (ret != EXIT_SUCCESS)
return ret;
mcc___int_op_shl (&cpy, bits);
mcc___int_op_shr (&cpy, bits);
mcc_int_size (&cpy, 0);
if (ret != EXIT_SUCCESS)
return ret;
}
return mcc___int_op_shl (num, move);
}
int
mcc__int_op_shr (mcc__int_t * num, mcc__int_t const *const val)
{
int ret = mcc_int_validate2 (num, val);
mcc__int_t tmp = { 0 }, cpy =
{
0}, rem =
{
0};
mcc_int_seg_t move = 0, bits = 0;
if (ret != EXIT_SUCCESS)
return ret;
bits = num->stop.b - num->zero.b;
ret = mcc_int_wrap (&tmp, &bits, 1);
if (ret != EXIT_SUCCESS)
return ret;
ret = mcc_int_wrap (&rem, &move, 1);
if (ret != EXIT_SUCCESS)
return ret;
move = *(val->zero.seg);
if (mcc__int_is_gte (val, &tmp))
{
ret = mcc_int_size_and_fill (&cpy, val->zero.seg, val->size);
if (ret != EXIT_SUCCESS)
return ret;
mcc___int_op_shl (&cpy, bits);
mcc___int_op_shr (&cpy, bits);
mcc_int_size (&cpy, 0);
if (ret != EXIT_SUCCESS)
return ret;
}
return mcc___int_op_shr (num, move);
}
int
mcc__int_to_num (mcc__int_t * dst, mcc_int_seg_t num)
{
int ret = mcc__int_op_xor (dst, dst);
mcc__int_t tmp = { 0 };
if (ret != EXIT_SUCCESS)
return ret;
(void) mcc_int_wrap (&tmp, &num, 1);
return mcc__int_op_aor (dst, &tmp);
}
#ifndef INC_BITMATH
int
test (mcc_test_t num, char *op, mcc_test_t val)
{
int ret = EXIT_FAILURE;
mcc_test_t rem = num, b4 = num;
mcc__int_t _num = { 0 }, _val =
{
0}, _rem =
{
0};
(void) mcc_int_size_and_fill (&_num, &num, sizeof (num));
(void) mcc_int_size_and_fill (&_val, &val, sizeof (num));
(void) mcc_int_size_and_fill (&_rem, &num, sizeof (num));
switch (*op)
{
case 0:
ret = EILSEQ;
goto fail;
case '|':
num |= val;
mcc__int_op_aor (&_num, &_val);
goto done;
case '^':
num ^= val;
mcc__int_op_xor (&_num, &_val);
goto done;
case '&':
num &= val;
mcc__int_op_and (&_num, &_val);
goto done;
case '+':
num += val;
mcc__int_op_add (&_num, &_val);
goto done;
case '*':
num *= val;
mcc__int_op_mul (&_num, &_val);
goto done;
case '-':
num -= val;
mcc__int_op_sub (&_num, &_val);
goto done;
case '/':
if (val)
{
rem %= val;
num /= val;
}
else
{
rem = num;
num = 0;
}
mcc___int_op_div (&_num, &_val, &_rem);
goto done;
case '%':
if (val)
{
rem %= val;
num = rem;
}
else
{
rem = num;
}
mcc___int_op_div (&_num, &_val, &_rem);
memcpy (_num.zero.seg, _rem.zero.seg, _num.size);
goto done;
case '=':
if (op[1] != '=')
goto fail;
num = (num == val);
mcc__int_to_num (&_num, mcc__int_is_eql (&_num, &_val));
goto done;
case '!':
if (op[1] == '\0')
{
num = !num;
mcc__int_to_num (&_num, mcc__int_is_nil (&_num));
}
else if (op[1] == '=')
{
num = (num != val);
mcc__int_to_num (&_num, mcc__int_is_neq (&_num, &_val));
}
goto done;
case '>':
if (op[1] == '>')
{
num >>= val;
mcc__int_op_shr (&_num, &_val);
}
else if (op[1] == '=')
{
num = (num >= val);
mcc__int_to_num (&_num, mcc__int_is_gte (&_num, &_val));
}
else
{
num = (num > val);
mcc__int_to_num (&_num, mcc__int_is_gth (&_num, &_val));
}
goto done;
case '<':
if (op[1] == '<')
{
num <<= val;
mcc__int_op_shl (&_num, &_val);
}
else if (op[1] == '=')
{
num = (num <= val);
mcc__int_to_num (&_num, mcc__int_is_lte (&_num, &_val));
}
else
{
num = (num < val);
mcc__int_to_num (&_num, mcc__int_is_lth (&_num, &_val));
}
goto done;
}
done:
if (*((mcc_test_t *) (_num.zero.seg)) == num)
ret = EXIT_SUCCESS;
else
printf ("_num = %08" MCC_TEST_PRI_PFX "X, "
"num = %08" MCC_TEST_PRI_PFX "X, "
"b4 = %08" MCC_TEST_PRI_PFX "X, "
"val = %" MCC_TEST_PRI_PFX "u, "
"_rem = %08" MCC_TEST_PRI_PFX "X, "
"rem = %08" MCC_TEST_PRI_PFX "X "
"op = '%s'\n",
*((mcc_test_t *) (_num.zero.seg)), num, b4, val,
*((mcc_test_t *) (_rem.zero.seg)), rem, op);
fail:
mcc_int_size (&_num, 0);
mcc_int_size (&_val, 0);
mcc_int_size (&_rem, 0);
return ret;
}
#endif
#include <float.h>
#ifndef INC_BITMATH
#define bitsof(T) (CHAR_BIT * sizeof(T))
#include <limits.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#endif
typedef signed char schar;
typedef unsigned char uchar;
typedef unsigned long ulong;
typedef signed long long sllong;
typedef unsigned long long ullong;
#if 1
#define mcc_huge __int128
#define MCC_UHUGE_MAX ((unsigned __int128)-1)
#define MCC_HUGE_MAX ((__int128)(MCC_UHUGE_MAX >> 1))
#define MCC_HUGE_MIN ((__int128)~(MCC_UHUGE_MAX >> 1))
#else
#define mcc_huge long long
#define MCC_UHUGE_MAX ULLONG_MAX
#define MCC_HUGE_MAX LLONG_MAX
#define MCC_HUGE_MIN LLONG_MIN
#endif
typedef signed mcc_huge mcc_huge_t;
typedef unsigned mcc_huge mcc_uhuge_t;
#ifdef HALF_MANT_DIG
#define HALF_SCNa "%ha"
#define HALF_SCNf "%hf"
#define HALF_SCNe "%he"
#define HALF_MAN_BIT (HALF_MANT_DIG - 1)
#define HALF_EXP_BIT (bitsof(half) - HALF_MANT_DIG)
#endif
#define FLT_SCNa "%a"
#define FLT_SCNf "%f"
#define FLT_SCNe "%e"
#define FLT_MAN_BIT (FLT_MANT_DIG - 1)
#define FLT_EXP_BIT (bitsof(float) - FLT_MANT_DIG)
typedef union FLT_UNION
{
float fpn;
mcc_uhuge_t raw;
struct
{
mcc_uhuge_t man:FLT_MAN_BIT;
mcc_uhuge_t exp:FLT_EXP_BIT;
mcc_uhuge_t sig:1;
};
} FLT_UNION;
#define DBL_SCNa "%la"
#define DBL_SCNf "%lf"
#define DBL_SCNe "%le"
#define DBL_MAN_BIT (DBL_MANT_DIG - 1)
#define DBL_EXP_BIT (bitsof(double) - DBL_MANT_DIG)
typedef union DBL_UNION
{
double fpn;
mcc_uhuge_t raw;
struct
{
mcc_uhuge_t man:DBL_MAN_BIT;
mcc_uhuge_t exp:DBL_EXP_BIT;
mcc_uhuge_t sig:1;
};
} DBL_UNION;
#define LDBL_SCNa "%lla"
#define LDBL_SCNf "%llf"
#define LDBL_SCNe "%lle"
#define LDBL_MAN_BIT (LDBL_MANT_DIG - 1)
#define LDBL_EXP_BIT (bitsof(long double) - LDBL_MANT_DIG)
typedef union LDBL_UNION
{
long double fpn;
mcc_uhuge_t raw;
struct
{
mcc_uhuge_t man:LDBL_MAN_BIT;
mcc_uhuge_t exp:LDBL_EXP_BIT;
mcc_uhuge_t sig:1;
};
} LDBL_UNION;
#define FPN_PFX(VAL) FLT##_##VAL
#define FPN_MAX FPN_PFX(_MAX)
#define FPN_SCNa FPN_PFX(SCNa)
#define FPN_SCNf FPN_PFX(SCNf)
#define FPN_SCNe FPN_PFX(SCNe)
#define FPN_DIG FPN_PFX(DIG)
#define FPN_EPSILON FPN_PFX(EPSILON)
#define FPN_MAN_BIT FPN_PFX(MAN_BIT)
#define FPN_MANT_DIG FPN_PFX(MANT_DIG)
#define FPN_EXP_BIT FPN_PFX(EXP_BIT)
#define FPN_MAX_EXP FPN_PFX(MAX_EXP)
#define FPN_MIN_EXP FPN_PFX(MIN_EXP)
#define FPN_MAX_10_EXP FPN_PFX(MAX_10_EXP)
#define FPN_MIN_10_EXP FPN_PFX(MIN_10_EXP)
typedef FPN_PFX(UNION) FPN_UNION;
typedef struct mcc_flexable_fpn {
long man_bits;
long exp_bits;
mcc_uhuge_t negative;
mcc_uhuge_t num;
mcc_uhuge_t one;
mcc_uhuge_t fpn;
long exp;
long max_exp;
long min_exp;
long max_exp_digits;
long min_exp_digits;
ulong exp_bias;
mcc_uhuge_t base;
mcc_uhuge_t raw;
} mcc_flexable_fpn_t;
#define FPN_MAKE big_make
mcc_flexable_fpn_t fpn_make ( mcc_flexable_fpn_t flex );
mcc_flexable_fpn_t big_make ( mcc_flexable_fpn_t flex );
mcc_flexable_fpn_t fpn_read (
char *text, FPN_UNION *gcc, mcc_flexable_fpn_t flex );
char *fpn_text[] = {
"0",
"1", "10", "16", "100", "101",
"0.1", "0.01", "0.001", "0.101",
"1.1", "1.01", "1.001", "1.101", "3.14",
"1e+1", "1e+8", "1e+10", "1e+100", "3e+1",
"1e-1", "1e-8", "1e-10", "1e-100", "3e-1",
".1e+1", ".1e+8", ".1e+10", ".1e+100", ".3e+1",
".1e-1", ".1e-8", ".1e-10", ".1e-100", ".3e-1",
"1.1e+1", "1.1e+8", "1.1e+10", "1.1e+100", "3.1e+1",
"1.1e-1", "1.1e-8", "1.1e-10", "1.1e-100", "3.1e-1",
"3.14e+1", "3.14e+8", "3.14e+10", "3.14e+100",
"3.14e-1", "3.14e-8", "3.14e-10", "3.14e-100",
"-0",
"-1", "-10", "-16", "-100", "-101",
"-0.1", "-0.01", "-0.001", "-0.101",
"-1.1", "-1.01", "-1.001", "-1.101", "-3.14",
"-1e+1", "-1e+8", "-1e+10", "-1e+100", "-3e+1",
"-1e-1", "-1e-8", "-1e-10", "-1e-100", "-3e-1",
"-0.1e+1", "-0.1e+8", "-0.1e+10", "-0.1e+100", "-0.3e+1",
"-0.1e-1", "-0.1e-8", "-0.1e-10", "-0.1e-100", "-0.3e-1",
"-1.1e+1", "-1.1e+8", "-1.1e+10", "-1.1e+100", "-3.1e+1",
"-1.1e-1", "-1.1e-8", "-1.1e-10", "-1.1e-100", "-3.1e-1",
"-3.14e+1", "-3.14e+8", "-3.14e+10", "-3.14e+100",
"-3.14e-1", "-3.14e-8", "-3.14e-10", "-3.14e-100",
"0xA", "0xA0", "0xA6", "0xA00", "0xA0A",
"0x0.A", "0x0.0A", "0x0.00A", "0x0.A0A",
"0xA.A", "0xA.0A", "0xA.00A", "0xA.A0A", "0xC.A4",
"0xAp+A", "0xAp+F", "0xAp+A0", "0xAp+A00", "0xCp+A",
"0xAp-A", "0xAp-F", "0xAp-A0", "0xAp-A00", "0xCp-A",
"0x0.Ap+A", "0x0.Ap+F", "0x0.Ap+A0", "0x0.Ap+A00", "0x0.Cp+A",
"0x0.Ap-A", "0x0.Ap-F", "0x0.Ap-A0", "0x0.Ap-A00", "0x0.Cp-A",
"0xA.Ap+A", "0xA.Ap+F", "0xA.Ap+A0", "0xA.Ap+A00", "0xC.Ap+A",
"0xA.Ap-A", "0xA.Ap-F", "0xA.Ap-A0", "0xA.Ap-A00", "0xC.Ap-A",
"0xC.A4p+A", "0xC.A4p+F", "0xC.A4p+A0", "0xC.A4p+A00",
"0xC.A4p-A", "0xC.A4p-F", "0xC.A4p-A0", "0xC.A4p-A00",
"-0xA", "-0xA0", "-0x10", "-0xA00", "-0xA0A",
"-0x0.A", "-0x0.0A", "-0x0.00A", "-0x0.A0A",
"-0xA.A", "-0xA.0A", "-0xA.00A", "-0xA.A0A", "-0xC.A4",
"-0xAp+A", "-0xAp+F", "-0xAp+A0", "-0xAp+A00", "-0xCp+A",
"-0xAp-A", "-0xAp-F", "-0xAp-A0", "-0xAp-A00", "-0xCp-A",
"-0x0.Ap+A", "-0x0.Ap+F", "-0x0.Ap+A0", "-0x0.Ap+A00", "-0x0.Cp+A",
"-0x0.Ap-A", "-0x0.Ap-F", "-0x0.Ap-A0", "-0x0.Ap-A00", "-0x0.Cp-A",
"-0xA.Ap+A", "-0xA.Ap+F", "-0xA.Ap+A0", "-0xA.Ap+A00", "-0xC.Ap+A",
"-0xA.Ap-A", "-0xA.Ap-F", "-0xA.Ap-A0", "-0xA.Ap-A00", "-0xC.Ap-A",
"-0xC.A4p+A", "-0xC.A4p+F", "-0xC.A4p+A0", "-0xC.A4p+A00",
"-0xC.A4p-A", "-0xC.A4p-F", "-0xC.A4p-A0", "-0xC.A4p-A00",
NULL
};
void printb( char const *text, void const * addr, size_t const bits ) {
size_t size = bits / CHAR_BIT, b = 0;
uchar const *a = addr;
uchar val, bit;
if ( bits % CHAR_BIT ) ++size;
printf("%s",text);
while ( size-- ) {
for ( val = a[size], bit = 1; bit; val <<= 1, bit <<= 1, ++b )
putchar( '0' + !!(val & SCHAR_MIN) );
if ( b >= bits ) return;
}
}
mcc_flexable_fpn_t copy_of_temp = {0};
size_t tested = 0, offby1 = 0, notinf = 0, wasinf = 0, noteql = 0;
_Bool check(
char *text, FPN_UNION gcc, FPN_UNION mcc, mcc_flexable_fpn_t flex ) {
_Bool same = (gcc.raw == mcc.raw), similar = 0, inf = 0;
FPN_UNION tmp = mcc;
ulong val;
tmp.raw--;
++tested;
noteql += !same;
if ( gcc.exp != mcc.exp ) {
inf = (gcc.exp == UCHAR_MAX || mcc.exp == UCHAR_MAX);
notinf += (gcc.exp == UCHAR_MAX);
wasinf += (mcc.exp == UCHAR_MAX);
}
similar = (gcc.man == tmp.man);
offby1 += similar;
if ( !same ) {
if ( !similar && !inf ) {
printb( "gcc = ", &gcc, bitsof(mcc_uhuge_t) );
putchar('\n');
printb( "mcc = ", &mcc, bitsof(mcc_uhuge_t) );
putchar('\n');
val = gcc.exp;
printb( "gcc.exp = ", &val, 11 );
putchar('\n');
val = mcc.exp;
printb( "mcc.exp = ", &val, 11 );
putchar('\n');
printf ("fpn t = " FPN_SCNe " m = " FPN_SCNe "\n",
gcc.fpn, mcc.fpn );
}
if ( inf ) {
printf("one = %llu, ", (ullong)(flex.one) );
printf("given %s", flex.negative ? "-" : "" );
if ( flex.base == 10 ) {
if ( flex.exp < 0 ) printf( "%llu.%llue%ld",
(ullong)(flex.num), (ullong)(flex.fpn), flex.exp );
else printf( "%llu.%llue+%ld",
(ullong)(flex.num), (ullong)(flex.fpn), flex.exp );
}
else
{
if ( flex.exp < 0 ) printf( "%llX.%llXp-%lX",
(ullong)(flex.num), (ullong)(flex.fpn), flex.exp );
else printf( "%llX.%llXp+%lX",
(ullong)(flex.num), (ullong)(flex.fpn), flex.exp );
}
printf (", value %s", text );
}
}
return !same;
}
void tried( char *pfx, size_t count, size_t not_eql,
size_t off_by1, size_t not_inf, size_t was_inf ) {
char *space = pfx ? " " : "";
if ( !pfx ) pfx = "";
printf(
"%s%sTried = %zu, "
"%s%sWrong = %zu, "
"%s%sOff By 1 = %zu, "
"%s%sNot Inf = %zu, "
"%s%sWas Inf = %zu\n",
pfx, space, count,
pfx, space, not_eql,
pfx, space, off_by1,
pfx, space, not_inf,
pfx, space, was_inf );
}
#define TEST_INT 1
#define TEST_NEG 0
#define TEST_FPN 0
#define TEST_BOTH 0
#define TEST_RAW 1
#define TEST_TEXT 0
#define TEST_WITH_LOOP 1
void exponent( mcc_flexable_fpn_t flex, size_t limit ) {
mcc_flexable_fpn_t temp;
FPN_UNION gcc = {0}, mcc = {0};
size_t i = 0;
char text[128] = {0}, etxt[8] = {0};
if ( flex.exp >= 0 )
snprintf(etxt, 8, "e+%ld",flex.exp);
else if ( flex.exp < 0 )
snprintf(etxt, 8, "e%ld",flex.exp);
#if TEST_INT
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"%zu.0%s",i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.num = i;
temp.one = 1;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-%zu.0%s",i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.negative = 1;
temp.num = i;
temp.one = 1;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
#endif
#if TEST_FPN
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"0.%zu%s",i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.fpn = i;
temp.one = 1;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-0.%zu%s",i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.negative = 1;
temp.fpn = i;
temp.one = 1;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
#endif
#if TEST_BOTH
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"%zu.%zu%s",i,i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.num = i;
temp.fpn = i;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-%zu.%zu%s",i,i,etxt);
#if TEST_RAW
sscanf( text, FPN_SCNe, &(gcc.fpn) );
temp = flex;
temp.negative = 1;
temp.num = i;
temp.fpn = i;
temp.one = 1;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
mcc.raw = (temp = FPN_MAKE(temp)).raw;
#else
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
#endif
check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
#endif
}
size_t scenario = 0;
int main ()
{
long i = 0;
#if TEST_WITH_LOOP
size_t limit = FPN_MAX_10_EXP;
#endif
#if TEST_TEXT
FPN_UNION gcc, mcc;
#endif
mcc_flexable_fpn_t flex = {0}, temp;
#if 0
printf("FPN_DIG %d\n", FPN_DIG );
printf("FPN_EXP_BIT %lu\n", FPN_EXP_BIT );
printf("FPN_EPSILON %le\n", FPN_EPSILON );
printf("FPN_MAX_EXP %d\n", FPN_MAX_EXP );
printf("FPN_MIN_EXP %d\n", FPN_MIN_EXP );
printf("FPN_MAX_10_EXP %d\n", FPN_MAX_10_EXP );
printf("FPN_MIN_10_EXP %d\n", FPN_MIN_10_EXP );
printf("FPN_MANT_DIG %d\n", FPN_MANT_DIG );
printf("FPN_MAN_BIT %d\n", FPN_MAN_BIT );
#endif
flex.one = 1;
flex.base = 10;
flex.exp_bias = FPN_MAX_EXP;
flex.exp_bits = FPN_EXP_BIT;
flex.max_exp_digits = FPN_MAX_10_EXP;
flex.min_exp_digits = FPN_MIN_10_EXP;
flex.max_exp = FPN_MAX_EXP;
flex.min_exp = FPN_MIN_EXP;
flex.man_bits = FPN_MAN_BIT;
printf( "flex.exp_bias = %ld\n", flex.exp_bias );
printf( "flex.exp_bits = %ld\n", flex.exp_bits );
printf( "flex.max_exp_digits = %ld\n", flex.max_exp_digits );
printf( "flex.min_exp_digits = %ld\n", flex.min_exp_digits );
printf( "flex.max_exp = %ld\n", flex.max_exp );
printf( "flex.min_exp = %ld\n", flex.min_exp );
printf( "flex.man_bits = %ld\n", flex.man_bits );
#if TEST_WITH_LOOP
temp = flex;
for ( i = 0; i <= limit; ++i ) {
temp.exp = -i;
exponent( temp, limit );
temp.exp = -(temp.exp);
}
tried( NULL, tested, noteql, offby1, notinf, wasinf );
printf("scenario = %zu\n", scenario );
#endif
#if TEST_TEXT
tested = 0; noteql = 0; offby1 = 0; notinf = 0; wasinf = 0;
for ( i = 0; fpn_text[i]; ++i ) {
mcc.raw = (temp = fpn_read (fpn_text[i], &gcc, flex)).raw;
check(fpn_text[i], gcc, mcc, temp);
putchar('\n');
}
while (fpn_text[i]) ++i;
printf( "Strings = %zu\n", i );
tried( "Text", tested, noteql, offby1, notinf, wasinf );
#endif
return 0;
}
mcc_flexable_fpn_t fpn_make ( mcc_flexable_fpn_t flex )
{
mcc_flexable_fpn_t temp = flex;
long pos = 0, pos_max = flex.man_bits;
mcc_uhuge_t NUM, inf = 0;
mcc_int_t num = {0}, fpn = {0}, one = {0}, base = {0};
inf = ~inf;
inf <<= flex.exp_bits;
inf = ~inf;
flex.raw = 0;
temp.negative <<= temp.man_bits;
temp.negative <<= temp.exp_bits;
if ( !(temp.num) && !(temp.fpn) ) goto fpn_sign;
/* Use exponent */
pos = temp.exp;
temp.raw = 0;
temp.raw = ~(temp.raw);
temp.raw <<= temp.max_exp - 1;
temp.raw = ~(temp.raw);
if ( pos < temp.min_exp || pos > temp.max_exp )
{
fpn_inf:
flex.raw = 0;
temp.raw = inf;
goto fpn_exp;
}
(void)mcc_int_wrap( &num, &(temp.num), 1 );
(void)mcc_int_wrap( &fpn, &(temp.fpn), 1 );
(void)mcc_int_wrap( &one, &(temp.one), 1 );
(void)mcc_int_wrap( &base, &(temp.base), 1 );
while ( pos > 0 && temp.fpn ) {
if ( mcc__int_op_mul( &num, &base ) == EOVERFLOW )
goto fpn_inf;
temp.one /= temp.base;
if ( temp.fpn >= temp.one ) {
NUM = temp.fpn / temp.one;
temp.num += NUM;
temp.fpn -= NUM * temp.one;
}
--pos;
}
while ( pos > 0 ) {
if ( mcc__int_op_mul( &num, &base ) == EOVERFLOW )
goto fpn_inf;
--pos;
}
(void)memset( &num, 0, sizeof(num) );
(void)mcc_int_wrap( &num, &NUM, 1 );
while ( pos < 0 && temp.num ) {
NUM = temp.num % temp.base;
temp.num /= temp.base;
if ( mcc__int_op_mul( &num, &one ) == EOVERFLOW )
goto fpn_inf;
temp.fpn += NUM;
if ( mcc__int_op_mul( &one, &base ) == EOVERFLOW )
goto fpn_inf;
pos++;
}
while ( pos < 0 ) {
if ( mcc__int_op_mul( &one, &base ) == EOVERFLOW )
goto fpn_inf;
pos++;
}
/* Set exponent */
pos = 0;
if ( temp.num ) {
NUM = temp.num;
while ( NUM > 1u ) {
NUM >>= 1;
++pos;
}
if ( pos > temp.max_exp ) goto fpn_inf;
}
else {
NUM = temp.fpn;
while ( NUM && NUM < temp.one )
{
NUM <<= 1;
--pos;
}
}
temp.raw = temp.exp_bias + pos - 1;
if ( temp.raw >= inf ) goto fpn_inf;
/* Set mantissa */
flex.raw = temp.num;
if ( pos > pos_max ) {
pos -= pos_max;
flex.raw >>= pos - 1;
temp.fpn = flex.raw & 1u;
flex.raw >>= 1;
temp.one = 2;
}
else {
for ( ; pos < pos_max; ++pos)
{
temp.fpn *= 2;
flex.raw <<= 1;
if ( temp.fpn >= temp.one )
{
flex.raw |= 1;
temp.fpn -= temp.one;
}
}
}
temp.fpn *= 2;
if ( temp.fpn >= temp.one ) flex.raw++;
temp.one = bitsof(mcc_uhuge_t) - (temp.man_bits);
flex.raw <<= temp.one;
flex.raw >>= temp.one;
fpn_exp:
flex.raw |= (temp.raw << temp.man_bits);
fpn_sign:
flex.raw |= temp.negative;
copy_of_temp = temp;
return flex;
}
mcc_flexable_fpn_t big_make ( mcc_flexable_fpn_t flex )
{
int ret = 0;
mcc_flexable_fpn_t temp = flex;
long pos = 0, pos_max = flex.man_bits;
mcc_int_t NUM = {0}, num = {0}, fpn = {0},
one = {0}, base = {0}, rem = {0}, tmp = {0};
mcc_uhuge_t inf = 0;
inf = ~inf;
inf <<= flex.exp_bits;
inf = ~inf;
flex.raw = 0;
temp.negative <<= temp.man_bits;
temp.negative <<= temp.exp_bits;
if ( !(temp.num) && !(temp.fpn) ) goto big_sign;
ret = mcc_int_size( &num, (temp.max_exp / CHAR_BIT) + 1 );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &rem, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &fpn, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &NUM, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &one, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &tmp, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
ret = mcc_int_size( &base, num.size );
if ( ret != EXIT_SUCCESS ) goto big_sign;
memset( NUM.zero.seg, 0, NUM.size );
memset( num.zero.seg, 0, num.size );
memset( fpn.zero.seg, 0, fpn.size );
memset( one.zero.seg, 0, one.size );
memset( base.zero.seg, 0, base.size );
memset( tmp.zero.seg, 0, tmp.size );
memcpy( num.zero.seg, &temp.num, sizeof(temp.num) );
memcpy( fpn.zero.seg, &temp.fpn, sizeof(temp.fpn) );
memcpy( one.zero.seg, &temp.one, sizeof(temp.one) );
memcpy( base.zero.seg, &temp.base, sizeof(temp.base) );
*(tmp.zero.seg) = 1;
while ( NUM.stop.bit > 1 ) num.stop = mcc_bit_op_dec(NUM.stop);
while ( num.stop.bit > 1 ) num.stop = mcc_bit_op_dec(num.stop);
while ( fpn.stop.bit > 1 ) fpn.stop = mcc_bit_op_dec(fpn.stop);
while ( one.stop.bit > 1 ) one.stop = mcc_bit_op_dec(one.stop);
while ( base.stop.bit > 1 ) base.stop = mcc_bit_op_dec(base.stop);
while ( tmp.stop.bit > 1 ) tmp.stop = mcc_bit_op_dec(tmp.stop);
/* Use exponent */
pos = temp.exp;
if ( pos < temp.min_exp || pos > temp.max_exp )
{
big_inf:
flex.raw = 0;
temp.raw = inf;
goto big_exp;
}
while ( pos > 0 && !mcc__int_is_nil(&fpn) ) {
if ( mcc__int_op_mul( &num, &base ) == EOVERFLOW )
goto big_inf;
mcc___int_op_div( &one, &base, &rem );
if ( mcc__int_is_gte( &fpn, &one ) ) {
memcpy( NUM.zero.seg, fpn.zero.seg, fpn.size );
mcc___int_op_div( &NUM, &one, &rem );
mcc__int_op_add( &num, &NUM );
mcc__int_op_mul( &NUM, &one );
mcc__int_op_sub( &fpn, &NUM );
}
--pos;
}
while ( pos > 0 ) {
if ( mcc__int_op_mul( &num, &base ) == EOVERFLOW )
goto big_inf;
--pos;
}
while ( pos < 0 && !mcc__int_is_nil(&num) ) {
mcc___int_op_div( &num, &base, &NUM );
if ( mcc__int_op_mul( &NUM, &one ) == EOVERFLOW )
goto big_inf;
if ( mcc__int_op_add( &fpn, &NUM ) == EOVERFLOW )
goto big_inf;
if ( mcc__int_op_mul( &one, &base ) == EOVERFLOW )
goto big_inf;
pos++;
}
while ( pos < 0 ) {
if ( mcc__int_op_mul( &one, &base ) == EOVERFLOW )
goto big_inf;
pos++;
}
/* Set exponent */
pos = 0;
if ( !mcc__int_is_nil( &num ) ) {
memcpy( NUM.zero.seg, num.zero.seg, num.size );
while ( mcc__int_is_gth( &NUM, &tmp ) ) {
mcc___int_op_shr( &NUM, 1 );
++pos;
}
if ( pos > temp.max_exp ) goto big_inf;
}
else {
memcpy( NUM.zero.seg, fpn.zero.seg, fpn.size );
while (
!mcc__int_is_nil( &NUM ) && mcc__int_is_lth( &NUM, &one ) )
{
mcc___int_op_shl( &NUM, 1 );
--pos;
}
}
temp.raw = temp.exp_bias + pos - 1;
if ( temp.raw >= inf ) goto big_inf;
/* Set mantissa */
memcpy( &(flex.raw), num.zero.seg, sizeof(mcc_uhuge_t) );
if ( pos > pos_max ) {
memset( fpn.zero.seg, 0, fpn.size );
memset( one.zero.seg, 0, one.size );
pos -= pos_max;
mcc___int_op_shr( &num, pos - 1 );
*(fpn.zero.seg) = (*(num.zero.seg) & 1u);
mcc___int_op_shr( &num, 1 );
memcpy( &(flex.raw), num.zero.seg, sizeof(mcc_uhuge_t) );
*(one.zero.seg) = 2;
}
else {
*(tmp.zero.seg) = 2;
if ( pos < temp.min_exp ) {
pos -= temp.min_exp;
pos = -pos;
printf("pos = %ld\n", pos );
mcc___int_op_shr( &fpn, pos );
mcc___int_op_shr( &one, pos );
pos = temp.min_exp;
}
for ( ; pos < pos_max; ++pos)
{
mcc___int_op_shl( &fpn, 1 );
//mcc___int_op_mul( &fpn, &tmp, &NUM );
flex.raw <<= 1;
if ( mcc__int_is_gte(&fpn, &one) )
{
flex.raw |= 1;
mcc__int_op_sub( &fpn, &one );
}
}
}
mcc___int_op_shl( &fpn, 1 );
if ( mcc__int_is_gte(&fpn, &one) )
flex.raw++;
temp.one = (bitsof(mcc_uhuge_t) - temp.man_bits);
flex.raw <<= temp.one;
flex.raw >>= temp.one;
big_exp:
flex.raw |= (temp.raw << temp.man_bits);
big_sign:
flex.raw |= temp.negative;
copy_of_temp = temp;
mcc_int_size( &base, 0 );
mcc_int_size( &one, 0 );
mcc_int_size( &NUM, 0 );
mcc_int_size( &fpn, 0 );
mcc_int_size( &rem, 0 );
mcc_int_size( &num, 0 );
return flex;
}
mcc_flexable_fpn_t fpn_read (
char *text, FPN_UNION *gcc, mcc_flexable_fpn_t flex )
{
uchar *txt = (uchar*)text;
ulong c;
gcc->raw = 0;
flex.raw = 0;
flex.base = 10;
flex.negative = (*txt == '-');
if ( flex.negative || *txt == '+' )
++txt;
if ( *txt =='0' ) {
++txt;
if ( *txt == 'x' || *txt == 'X' ) {
flex.base = 16;
++txt;
}
}
if ( flex.base == 10 )
sscanf (text, FPN_SCNf, &(gcc->fpn));
else
sscanf (text, FPN_SCNa, &(gcc->fpn));
while (*txt == '0') ++txt;
for ( flex.num = 0; *txt; ++txt ) {
if ( *txt >= '0' && *txt <= '9' )
c = *txt - '0';
else if ( *txt >= 'A' && *txt <= 'F' )
c = 10 + ( *txt - 'A' );
else if ( *txt >= 'a' && *txt <= 'f' )
c = 10 + ( *txt - 'a' );
else break;
if ( c >= flex.base ) break;
flex.num *= flex.base;
flex.num += c;
}
flex.one = 1;
flex.fpn = 0;
if (*txt == '.')
{
for ( ++txt; *txt; ++txt)
{
if ( *txt >= '0' && *txt <= '9' )
c = *txt - '0';
else if ( *txt >= 'A' && *txt <= 'F' )
c = 10 + ( *txt - 'A' );
else if ( *txt >= 'a' && *txt <= 'f' )
c = 10 + ( *txt - 'a' );
else break;
if ( c >= flex.base ) break;
flex.one *= flex.base;
flex.fpn *= flex.base;
flex.fpn += c;
}
}
if (*txt == 'e' || *txt == 'E')
{
if (*(++txt) == '-')
{
for (++txt; *txt; ++txt)
{
if ( *txt >= '0' && *txt <= '9' )
c = *txt - '0';
else if ( *txt >= 'A' && *txt <= 'F' )
c = 10 + ( *txt - 'A' );
else if ( *txt >= 'a' && *txt <= 'f' )
c = 10 + ( *txt - 'f' );
else break;
if ( c >= flex.base ) break;
flex.exp *= flex.base;
flex.exp -= c;
}
}
else
{
for (++txt; *txt; ++txt)
{
if ( *txt >= '0' && *txt <= '9' )
c = *txt - '0';
else if ( *txt >= 'A' && *txt <= 'F' )
c = 10 + ( *txt - 'A' );
else if ( *txt >= 'a' && *txt <= 'f' )
c = 10 + ( *txt - 'f' );
else break;
if ( c >= flex.base ) break;
flex.exp *= flex.base;
flex.exp += c;
}
}
}
return FPN_MAKE(flex);
}