#define INC_BITMATH
#include <limits.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define bitsof(T) (CHAR_BIT * sizeof(T))
#ifndef INC_BITMATH
int test( int num, char *op, int val );
char *operations[] = {
"==", "!=", ">", ">=", "<", "<=",
"<<", ">>", "|", "&", "^",
"+", "*", "-", "/", NULL, "%",
NULL };
int main() {
int num = 1024, val = 16, i;
for ( i = 0; operations[i]; ++i ) {
test( num, operations[i], val );
}
return 0;
}
#endif
typedef unsigned long mcc_int_seg_t;
#define BI_SEG_END_BIT (~(ULONG_MAX >> 1))
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 inc_mcc_bit( mcc_bit_t num ) {
++(num.b);
num.bit <<= 1;
if ( !(num.bit) ) {
num.bit = 1;
++(num.i);
++(num.seg);
}
return num;
}
mcc_bit_t add_mcc_bit( mcc_bit_t num, mcc_int_seg_t bits ) {
mcc_int_seg_t i = 0;
if ( !(num.b) ) goto add_mcc_bit_bytes;
while ( bits && num.b % bitsof(mcc_int_seg_t) ) {
--bits;
num = inc_mcc_bit(num);
}
add_mcc_bit_bytes:
if ( !bits ) return num;
i = bits / bitsof(mcc_int_seg_t);
num.i += i;
num.seg = &(num.seg[i]);
num.bit = 1u << (bits % bitsof(mcc_int_seg_t));
if ( bits > bitsof(mcc_int_seg_t) && num.bit > 1u ) {
++(num.seg); ++(num.i);
}
num.b += bits;
return num;
}
mcc_bit_t dec_mcc_bit( mcc_bit_t num ) {
mcc_bit_t tmp = num;
--(tmp.b);
tmp.bit >>= 1;
if ( !(tmp.bit) ) {
tmp.bit = BI_SEG_END_BIT;
--(tmp.i);
--(tmp.seg);
}
return tmp;
}
mcc_bit_t sub_mcc_bit( mcc_bit_t num, mcc_int_seg_t bits ) {
mcc_int_seg_t i = 0;
if ( !(num.b) ) goto sub_mcc_bit_bytes;
while ( bits && num.b % bitsof(mcc_int_seg_t) ) {
--bits;
num = dec_mcc_bit(num);
}
sub_mcc_bit_bytes:
if ( !bits ) return num;
i = bits / bitsof(mcc_int_seg_t);
if ( bits % bitsof(mcc_int_seg_t) ) ++i;
num.i -= i;
while ( i-- ) --(num.seg);
num.bit = BI_SEG_END_BIT;
num.bit >>= (bits % bitsof(mcc_int_seg_t));
num.b -= bits;
return num;
}
int cmp_mcc_bit( mcc_bit_t num, mcc_bit_t val ) {
if ( num.b > val.b ) return 1;
if ( num.b < val.b ) return -1;
return 0;
}
typedef struct _bi {
size_t size;
mcc_bit_t zero, stop;
} mcc_int_t;
int mcc_int_validate( mcc_int_t const * const num ) {
if ( !num || !(num->zero.seg) || !(num->stop.seg) )
return EADDRNOTAVAIL;
if ( cmp_mcc_bit( 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 bitemp( 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 = add_mcc_bit( 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;
++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;
memset( &(dst->zero), 0, sizeof(mcc_bit_t) );
dst->zero.seg = mem;
dst->zero.bit = 1;
size -= sizeof(mcc_int_seg_t);
dst->size = size;
dst->stop = add_mcc_bit( 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 cmp__mcc_int( mcc_int_t const * const num, mcc_int_t const * const val ) {
mcc_bit_t n, v;
if ( !num || !(num->zero.seg) || !(num->size) ) {
if ( !val ) return 0;
v = val->stop;
while ( v.b ) {
v = dec_mcc_bit(v);
if ( *(v.seg) & v.bit ) return -1;
}
return 0;
}
n = num->stop;
if ( !val || !(val->zero.seg) || !(val->size) ) {
while ( n.b ) {
n = dec_mcc_bit(n);
if ( *(n.seg) & n.bit ) return -1;
}
return 0;
}
v = val->stop;
while ( n.b || v.b ) {
while ( n.b ) {
n = dec_mcc_bit(n);
if ( *(n.seg) & n.bit ) break;
}
while ( v.b ) {
v = dec_mcc_bit(v);
if ( *(v.seg) & v.bit ) break;
}
if ( n.b != v.b ) return ( n.b > v.b ) ? 1 : -1;
}
return 0;
}
#define eql__mcc_int( num, val ) (cmp__mcc_int( num, val ) == 0)
#define neq__mcc_int( num, val ) (cmp__mcc_int( num, val ) != 0)
#define gth__mcc_int( num, val ) (cmp__mcc_int( num, val ) > 0)
#define gte__mcc_int( num, val ) (cmp__mcc_int( num, val ) >= 0)
#define lth__mcc_int( num, val ) (cmp__mcc_int( num, val ) < 0)
#define lte__mcc_int( num, val ) (cmp__mcc_int( 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 = dec_mcc_bit(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 = dec_mcc_bit(pos = num->stop);
while ( pos.i == one.i ) {
if ( *(pos.seg) & pos.bit )
*(pos.seg) ^= pos.bit;
}
return EXIT_SUCCESS;
}
int add__mcc_int( mcc_int_t *num, mcc_int_t const * const val ) {
mcc_bit_t n, v, stop;
_Bool c = 0;
int ret = mcc_int_validate2( num, val );
if ( ret != EXIT_SUCCESS ) return ret;
stop = (cmp_mcc_bit(num->stop,val->stop) < 0) ? num->stop : val->stop;
for ( n = num->zero, v = val->zero; n.b < stop.b && v.b < stop.b;
n = inc_mcc_bit(n), v = inc_mcc_bit(v) ) {
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;
}
}
if ( c ) {
for ( ; n.b < stop.b; n = inc_mcc_bit(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 = add__mcc_int( 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 = dec_mcc_bit(tmp.stop);
ret = add__mcc_int( &tmp, val );
if ( ret == EOVERFLOW ) {
memset( num->zero.seg, -1, num->size );
ret = biclamp0( &tmp );
}
return ret;
}
int shl___mcc_int( mcc_int_t *num, mcc_int_seg_t bits ) {
int ret = mcc_int_validate( num );
mcc_bit_t n, v;
if ( ret != EXIT_SUCCESS ) return ret;
if ( !bits ) return EXIT_SUCCESS;
v = sub_mcc_bit( num->stop, bits - 1 );
n = num->stop;
while ( v.b ) {
n = dec_mcc_bit(n);
v = dec_mcc_bit(v);
if ( *(v.seg) & v.bit )
*(n.seg) |= n.bit;
else if ( *(n.seg) & n.bit )
*(n.seg) ^= n.bit;
}
while ( n.bit >> 1 ) {
n = dec_mcc_bit(n);
if ( *(n.seg) & n.bit )
*(n.seg) ^= n.bit;
}
if ( n.i ) memset( num->zero.seg, 0, n.i * sizeof(mcc_int_seg_t) );
return EXIT_SUCCESS;
}
int shl__mcc_int( 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 = bitemp( &tmp, &(num->stop.b), 1 );
if ( ret != EXIT_SUCCESS ) return ret;
if ( gte__mcc_int( val, &tmp ) ) {
memset( num->zero.seg, 0, num->size );
return EXIT_SUCCESS;
}
return shl___mcc_int( num, *(val->zero.seg) );
}
int shr___mcc_int( mcc_int_t *num, mcc_int_seg_t bits ) {
int ret = mcc_int_validate( num );
mcc_bit_t n, v;
if ( ret != EXIT_SUCCESS ) return ret;
if ( !bits ) return EXIT_SUCCESS;
v = add_mcc_bit( num->zero, bits );
n = num->zero;
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 = inc_mcc_bit(n);
v = inc_mcc_bit(v);
}
while ( n.bit > 1u ) {
if ( *(n.seg) & n.bit )
*(n.seg) ^= n.bit;
n = inc_mcc_bit(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 shr__mcc_int( 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 = bitemp( &tmp, &(num->stop.b), 1 );
if ( ret != EXIT_SUCCESS ) return ret;
if ( gte__mcc_int( val, &tmp ) ) {
memset( num->zero.seg, 0, num->size );
return EXIT_SUCCESS;
}
return shr___mcc_int(num, *(val->zero.seg) );
}
int aor__mcc_int( 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 = (cmp_mcc_bit(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 = inc_mcc_bit(n);
v = inc_mcc_bit(v);
}
return EXIT_SUCCESS;
}
int xor__mcc_int( 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 = (cmp_mcc_bit(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 = inc_mcc_bit(n);
v = inc_mcc_bit(v);
}
return EXIT_SUCCESS;
}
int and__mcc_int( 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 = (cmp_mcc_bit(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 = inc_mcc_bit(n);
v = inc_mcc_bit(v);
}
while ( n.b < num->stop.b ) {
if ( *(n.seg) & n.bit )
*(n.seg) ^= n.bit;
n = inc_mcc_bit(n);
}
return EXIT_SUCCESS;
}
int mul__mcc_int( mcc_int_t *num, mcc_int_t const * const val ) {
int ret = mcc_int_validate2( num, val );
mcc_int_t tmp = {0};
mcc_bit_t v;
mcc_int_seg_t bits = 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;
memset( num->zero.seg, 0, num->size );
for ( v = val->zero; v.b < val->stop.b; v = inc_mcc_bit(v) ) {
if ( *(v.seg) & v.bit ) {
(void)shl___mcc_int( &tmp, bits );
if ( add__mcc_int( num, &tmp ) == EOVERFLOW )
ret = EOVERFLOW;
bits = 0;
}
++bits;
}
(void)mcc_int_size( &tmp, 0 );
return ret;
}
int sub__mcc_int( mcc_int_t *num, mcc_int_t const * const val ) {
mcc_bit_t n, v, stop;
_Bool c = 0;
int ret = mcc_int_validate2( num, val );
if ( ret != EXIT_SUCCESS ) return ret;
stop = (cmp_mcc_bit(num->stop,val->stop) < 0) ? num->stop : val->stop;
for ( n = num->zero, v = val->zero; n.b < stop.b && v.b < stop.b;
n = inc_mcc_bit(n), v = inc_mcc_bit(v) ) {
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;
}
}
if ( c ) {
for ( ; n.b < stop.b; n = inc_mcc_bit(n) ) {
*(n.seg) ^= n.bit;
if ( !(*(n.seg) & n.bit) ) {
c = 0;
break;
}
}
}
return c ? EOVERFLOW : EXIT_SUCCESS;
}
int div__mcc_int( mcc_int_t *num, mcc_int_t const * const val, mcc_int_t *rem ) {
int ret = mcc_int_validate2( num, val );
mcc_int_t seg = {0};
mcc_int_seg_t bits = 0;
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc_int_validate(rem);
if ( ret != EXIT_SUCCESS )
return (ret == EADDRNOTAVAIL) ? EDESTADDRREQ : ret;
if ( rem->size != num->size ) return ERANGE;
(void)memcpy( rem->zero.seg, num->zero.seg, num->size );
(void)memset( num->zero.seg, 0, num->size );
if ( eql__mcc_int( val, NULL ) ) return EXIT_SUCCESS;
seg = *rem;
while ( seg.stop.b ) {
seg.stop = dec_mcc_bit(seg.stop);
if ( *(seg.stop.seg) & seg.stop.bit ) {
seg.stop = inc_mcc_bit(seg.stop);
break;
}
}
seg.zero = seg.stop;
seg.zero = dec_mcc_bit(seg.zero);
while ( seg.zero.b ) {
if ( gte__mcc_int( &seg, val ) ) {
shl___mcc_int( num, bits );
sub__mcc_int( &seg, val );
*(num->zero.seg) |= num->zero.bit;
bits = 0;
}
++bits;
seg.zero = dec_mcc_bit(seg.zero);
}
if ( bits ) shl___mcc_int( num, bits );
return EXIT_SUCCESS;
}
#ifndef INC_BITMATH
int test( int num, char *op, int val ) {
int ret = EXIT_FAILURE, rem = num, b4 = num;
mcc_int_t _num = {0}, _val = {0}, _rem = {0};
(void)mcc_int_size_and_fill( &_num, &num, sizeof(int) );
(void)mcc_int_size_and_fill( &_val, &val, sizeof(int) );
(void)mcc_int_size_and_fill( &_rem, &num, sizeof(int) );
switch ( *op ) {
case 0: ret = EILSEQ; goto fail;
case '|': num |= val; aor__mcc_int( &_num, &_val ); goto done;
case '^': num ^= val; xor__mcc_int( &_num, &_val ); goto done;
case '&': num &= val; and__mcc_int( &_num, &_val ); goto done;
case '+': num += val; add__mcc_int( &_num, &_val ); goto done;
case '*': num *= val; mul__mcc_int( &_num, &_val ); goto done;
case '-': num -= val; sub__mcc_int( &_num, &_val ); goto done;
case '/':
num /= val; rem %= val;
div__mcc_int( &_num, &_val, &_rem ); goto done;
case '=':
if ( op[1] != '=' ) goto fail;
num = (num == val);
*(_num.zero.seg) = eql__mcc_int( &_num, &_val );
goto done;
case '!':
if ( op[1] != '=' ) goto fail;
num = (num != val);
*(_num.zero.seg) = neq__mcc_int( &_num, &_val );
goto done;
case '>':
if ( op[1] == '>' ) {
num = (num >> val);
shr__mcc_int( &_num, &_val );
}
else if ( op[1] == '=' ) {
num = (num >= val);
*(_num.zero.seg) = gte__mcc_int( &_num, &_val );
}
else {
num = (num > val);
*(_num.zero.seg) = gth__mcc_int( &_num, &_val );
}
goto done;
case '<':
if ( op[1] == '<' ) {
num = (num << val);
shl__mcc_int( &_num, &_val );
}
else if ( op[1] == '=' ) {
num = (num <= val);
*(_num.zero.seg) = lte__mcc_int( &_num, &_val );
}
else {
num = (num < val);
*(_num.zero.seg) = lth__mcc_int( &_num, &_val );
}
goto done;
}
done:
if ( memcmp( _num.zero.seg, &num, sizeof(int) ) )
ret = EXIT_SUCCESS;
printf( "_num = %08lX, num = %08X, b4 = %08X, val = %08X, "
"_rem = %08lX, rem = %08X op = '%s'\n",
*(_num.zero.seg), num, b4, val, *(_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>
#define INC_BITMATH
#ifdef INC_BITMATH
//#include "bimath.c"
#else
#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;
#define mcc_huge __int128
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_RADIX FPN_PFX(RADIX)
#define FPN_ROUNDS FPN_PFX(ROUNDS)
#define FPN_MAN_BIT FPN_PFX(MAN_BIT)
#define FPN_MAN_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_EXP_DIG FPN_PFX(MAX_10_EXP)
#define FPN_MIN_EXP_DIG 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;
ulong 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};
_Bool check(
char *text, FPN_UNION gcc, FPN_UNION mcc, mcc_flexable_fpn_t flex ) {
_Bool same = (gcc.raw == mcc.raw), similar;
mcc_flexable_fpn_t temp = flex;
ulong val;
temp.raw--;
similar = (gcc.raw == temp.raw);
if ( !same && !similar ) {
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 );
printf("read as %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(" with base %lu\n", flex.base );
printf ("value '%s'", text );
}
else {
temp = copy_of_temp;
}
return !same;
}
#define TEST_NEG 0
#define TEST_FPN 0
#define TEST_BOTH 0
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, wrong = 0, j = 0, total = 0;
char text[128] = {0}, etxt[8] = {0};
if ( flex.exp > 0 )
snprintf(etxt, 8, "e+%02ld",flex.exp);
else if ( flex.exp < 0 )
snprintf(etxt, 8, "e%02ld",flex.exp);
flex.exp = 0;
wrong = 0;
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"%zu.000000%s",i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-%zu.000000%s",i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
j += i * (1 + TEST_NEG); total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
#if TEST_FPN
wrong = 0;
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"0.%06zu%s",i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-0.%06zu%s",i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
j += i * (1 + TEST_NEG); total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
#endif
#if TEST_BOTH
wrong = 0;
for ( i = 0; i <= limit; ++i ) {
snprintf(text,128,"%zu.%06zu%s",i,i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#if TEST_NEG
snprintf(text,128,"-%zu.%06zu%s",i,i,etxt);
mcc.raw = (temp = fpn_read(text, &gcc, flex)).raw;
wrong += check( text, gcc, mcc, temp );
putchar('\n');
#endif
}
j += i * (1 + TEST_NEG); total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
#endif
if ( total ) printf( "Total Tried = %zu, Total Wrong = %zu\n", j, total );
}
int main ()
{
size_t i = 0, limit = 35;
#if 0
size_t wrong = 0;
FPN_UNION gcc, mcc;
#endif
mcc_flexable_fpn_t flex = {0}, temp;
printf("FLT_DIG %d\n", FLT_DIG );
printf("FLT_EXP_BIT %lu\n", FLT_EXP_BIT );
printf("FLT_EPSILON %le\n", FLT_EPSILON );
printf("FLT_MAX_EXP %d\n", FLT_MAX_EXP );
printf("FLT_MIN_EXP %d\n", FLT_MIN_EXP );
printf("FLT_MAX_10_EXP %d\n", FLT_MAX_10_EXP );
printf("FLT_MIN_10_EXP %d\n", FLT_MIN_10_EXP );
printf("FLT_MANT_DIG %d\n", FLT_MANT_DIG );
printf("FLT_MAN_BIT %d\n", FLT_MAN_BIT );
printf("FLT_RADIX %d\n", FLT_RADIX );
printf("FLT_ROUNDS %d\n", FLT_ROUNDS );
flex.exp_bias = FPN_MAX_EXP;
flex.exp_bits = FPN_EXP_BIT;
flex.max_exp_digits = FPN_MAX_EXP_DIG;
flex.min_exp_digits = FPN_MIN_EXP_DIG;
flex.max_exp = FPN_MAX_EXP;
flex.min_exp = FPN_MIN_EXP;
flex.man_bits = FPN_MAN_BIT;
temp = flex;
for ( i = 0; i <= FPN_MAX_EXP; ++i ) {
temp.exp = i;
exponent( temp, limit );
temp.exp = -(temp.exp);
}
#if 0
for ( i = 0; fpn_text[i] && i < 25; ++i ) {
mcc.raw = (temp = fpn_read (fpn_text[i], &gcc, flex));
if ( check(fpn_text[i], gcc, mcc, temp) ) {
printf (" index = %03zu\n", i );
++wrong;
}
}
printf( "Text Tried = %zu, ", i );
while (fpn_text[i]) ++i;
printf( "Text Wrong = %zu", wrong );
#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;
flex.raw = 0;
temp.negative <<= temp.man_bits;
temp.negative <<= temp.exp_bits;
if ( !(temp.num) && !(temp.fpn) ) {
flex.raw = temp.negative;
copy_of_temp = temp;
return flex;
}
if ( temp.exp < temp.min_exp ||
temp.exp > temp.max_exp )
{
fpn_infinity:
flex.raw = 0;
flex.raw = ~(flex.raw);
flex.raw <<= temp.exp_bits;
flex.raw = ~(flex.raw);
flex.raw <<= temp.man_bits;
flex.raw |= temp.negative;
copy_of_temp = temp;
return flex;
}
/* Preserve exponent in case we need it later */
pos = temp.exp;
while ( pos > 0 && temp.one > 1 ) {
temp.num *= temp.base;
temp.one /= temp.base;
if ( temp.fpn >= temp.one ) {
NUM = temp.fpn / temp.one;
temp.fpn -= NUM * temp.one;
temp.num += NUM;
}
--pos;
}
while ( pos > 0 ) {
temp.num *= temp.base;
--pos;
}
while ( pos < 0 ) {
NUM = temp.num % temp.base;
temp.fpn += NUM * temp.one;
temp.one *= temp.base;
temp.num /= temp.base;
pos++;
}
if ( !(temp.num) && !(temp.fpn) )
goto fpn_infinity;
/* Calculate normal exponent */
pos = 0;
if ( temp.num ) {
for ( NUM = temp.num; !(NUM & 1u); ++pos, NUM >>= 1 );
temp.raw = 0;
temp.raw = ~(temp.raw);
temp.raw <<= temp.man_bits + 1;
temp.raw = ~(temp.raw);
if ( pos > temp.max_exp_digits ) goto fpn_infinity;
for ( ; NUM > 1; ++pos, NUM >>= 1 );
}
else for ( NUM = temp.fpn; NUM && NUM < temp.one; --pos, NUM <<= 1 );
/* Set exponent and mantissa */
temp.raw = temp.exp_bias + pos - 1;
flex.raw = temp.num;
if ( pos <= temp.min_exp + 1 ) goto fpn_infinity;
if ( pos >= temp.max_exp - 1 ) goto fpn_infinity;
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 <<= 1;
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;
flex.raw |= (temp.raw << temp.man_bits);
flex.raw |= temp.negative;
copy_of_temp = temp;
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);
}
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}, cpy = {0};
flex.raw = 0;
temp.negative <<= temp.man_bits;
temp.negative <<= temp.exp_bits;
ret = mcc_int_size( &num, 32 );
if ( ret != EXIT_SUCCESS ) goto big_zero;
ret = mcc_int_size( &cpy, num.size );
if ( ret != EXIT_SUCCESS ) goto big_zero;
ret = mcc_int_size( &fpn, num.size );
if ( ret != EXIT_SUCCESS ) goto big_zero;
ret = mcc_int_size( &NUM, num.size );
if ( ret != EXIT_SUCCESS ) goto big_zero;
ret = mcc_int_size( &one, num.size );
if ( ret != EXIT_SUCCESS ) goto big_zero;
ret = mcc_int_size( &base, num.size );
if ( ret != EXIT_SUCCESS ) goto big_zero;
memset( num.zero.seg, 0, num.size );
memcpy( num.zero.seg, &temp.num, sizeof(mcc_uhuge_t) );
memset( fpn.zero.seg, 0, fpn.size );
memcpy( fpn.zero.seg, &temp.fpn, sizeof(mcc_uhuge_t) );
memset( NUM.zero.seg, 0, NUM.size );
memset( one.zero.seg, 0, one.size );
memcpy( one.zero.seg, &temp.one, sizeof(mcc_uhuge_t) );
memset( base.zero.seg, 0, base.size );
memcpy( base.zero.seg, &temp.base, sizeof(ulong) );
if ( !(temp.num) && !(temp.fpn) ) {
big_zero:
flex.raw = temp.negative;
copy_of_temp = temp;
goto big_free_all;
}
if ( temp.exp < temp.min_exp ||
temp.exp > temp.max_exp )
{
big_infinity:
flex.raw = 0;
flex.raw = ~(flex.raw);
flex.raw <<= temp.exp_bits;
flex.raw = ~(flex.raw);
flex.raw <<= temp.man_bits;
flex.raw |= temp.negative;
copy_of_temp = temp;
goto big_free_all;
}
/* Preserve exponent in case we need it later */
pos = temp.exp;
while ( pos > 0 && temp.one > 1 ) {
mul__mcc_int( &num, &base );
div__mcc_int( &num, &base, &cpy );
if ( gte__mcc_int( &fpn, &one ) ) {
memcpy( NUM.zero.seg, fpn.zero.seg, fpn.size );
div__mcc_int( &NUM, &one, &cpy );
add__mcc_int( &num, &NUM );
mul__mcc_int( &NUM, &one );
sub__mcc_int( &fpn, &NUM );
}
--pos;
}
while ( pos > 0 ) {
mul__mcc_int( &num, &base );
--pos;
}
while ( pos < 0 ) {
div__mcc_int( &num, &base, &NUM );
mul__mcc_int( &NUM, &one );
add__mcc_int( &fpn, &NUM );
mul__mcc_int( &one, &base );
pos++;
}
if ( eql__mcc_int(&num,NULL) && eql__mcc_int(&fpn,NULL) )
goto big_infinity;
/* Calculate normal exponent */
pos = 0;
if ( temp.num ) {
memcpy( NUM.zero.seg, num.zero.seg, num.size );
while ( !(*(NUM.zero.seg) & 1u ) ) {
shr___mcc_int( &NUM, 1 );
++pos;
}
temp.raw = 0;
temp.raw = ~(temp.raw);
temp.raw <<= temp.man_bits + 1;
temp.raw = ~(temp.raw);
if ( pos > temp.max_exp_digits ) goto big_infinity;
memset( cpy.zero.seg, 0, cpy.size );
*(cpy.zero.seg) = 1;
while ( gth__mcc_int( &NUM, &cpy ) ) {
shr___mcc_int( &NUM, 1 );
++pos;
}
}
else {
memcpy( NUM.zero.seg, fpn.zero.seg, fpn.size );
while ( neq__mcc_int( &NUM, NULL ) &&
lth__mcc_int( &NUM, &one ) )
{
shl___mcc_int( &NUM, 1 );
--pos;
}
}
/* Set exponent and mantissa */
temp.raw = temp.exp_bias + pos - 1;
memcpy( &(flex.raw), num.zero.seg, sizeof(mcc_uhuge_t) );
flex.raw = temp.num;
if ( pos <= temp.min_exp + 1 ) goto big_infinity;
if ( pos >= temp.max_exp - 1 ) goto big_infinity;
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)
{
shl___mcc_int( &fpn, 1 );
flex.raw <<= 1;
if ( gte__mcc_int(&fpn, &one) )
{
flex.raw |= 1;
sub__mcc_int( &fpn, &one );
}
}
}
shl___mcc_int( &fpn, 1 );
if ( gte__mcc_int(&fpn, &one) )
flex.raw++;
temp.one = bitsof(mcc_uhuge_t) - (temp.man_bits);
flex.raw <<= temp.one;
flex.raw >>= temp.one;
flex.raw |= (temp.raw << temp.man_bits);
flex.raw |= temp.negative;
copy_of_temp = temp;
big_free_all:
mcc_int_size( &base, 0 );
mcc_int_size( &one, 0 );
mcc_int_size( &NUM, 0 );
mcc_int_size( &fpn, 0 );
mcc_int_size( &cpy, 0 );
mcc_int_size( &num, 0 );
return flex;
}