#include "mcc_vflt.h"
#include <ctype.h>
mcc_fpn_t mcc_fpn_set_inf( mcc_fpn_t mcc );
mcc_fpn_t mcc_fpn_make( mcc_fpn_t tmp, mcc_fpn_t ret );
mcc_fpn_t mcc_fpn_read(
char *txt,
mcc_fpn_t *gcc,
mcc_fpn_t tmp,
mcc_fpn_t ret );
mcc_big_t mcc_big_set_inf( mcc_big_t mcc );
mcc_big_t mcc_big_make( mcc_big_t tmp, mcc_big_t ret );
mcc_big_t mcc_big_read(
char *txt,
mcc_big_t *gcc,
mcc_big_t tmp,
mcc_big_t ret );
void printb( char const *pfx, void * addr, size_t bits, char const *sfx ) {
mcc_bit_t b = {0};
b.seg = addr;
b.bit = 1;
b = mcc__bit_op_add( b, bits );
printf("%s",pfx);
while ( b.b ) {
b = mcc_bit_op_dec(b);
putchar( '0' + !!(*(b.seg) & b.bit) );
}
printf("%s",sfx);
}
typedef struct waswasnot {
uint was;
uint not;
} waswasnot_t;
waswasnot_t waswasnot_add( waswasnot_t num, waswasnot_t val ) {
num.was += val.was;
num.not += val.not;
return num;
}
void waswasnot_put( char *pfx, char *txt, waswasnot_t num, char *sfx ) {
printf("%s was %s %u, ", pfx, txt, num.was );
printf("%s not %s %u%s", pfx, txt, num.not, sfx );
}
typedef struct fpn_stats {
uint count;
waswasnot_t eql;
waswasnot_t mul;
waswasnot_t nil;
waswasnot_t inc;
waswasnot_t shl;
waswasnot_t inf;
} fpn_stats_t;
void fpn_stats_put( char *txt, char *pfx, fpn_stats_t stats ) {
float right = stats.eql.was, total = stats.count;
if ( !txt ) txt = "";
if ( !pfx ) pfx = "";
printf("%s() %s count %u %s\n", __func__, pfx, stats.count, txt );
waswasnot_put( pfx, "eql", stats.eql, "\n" );
waswasnot_put( pfx, "nil", stats.nil, "\n" );
waswasnot_put( pfx, "inc", stats.inc, "\n" );
waswasnot_put( pfx, "shl", stats.shl, "\n" );
waswasnot_put( pfx, "mul", stats.mul, "\n" );
waswasnot_put( pfx, "inf", stats.inf, "\n" );
printf( "%f%% Correct\n", (right / total) * 100.0 );
}
void details(
fpn_stats_t *dst, char const *txt,
mcc_fpn_t gcc, mcc_fpn_t mcc ) {
FPN_UNION _gcc = {0}, _mcc = {0};
ullong g = gcc.raw, m = mcc.raw;
fpn_stats_t stats = {0};
mcc_fpn_limits_t limits = mcc.limits;
stats.eql.was = (gcc.raw == mcc.raw);
stats.eql.not = !(stats.eql.was);
if ( stats.eql.was ) goto details_add;
_gcc.raw = gcc.raw;
_mcc.raw = mcc.raw;
_gcc.sig = 0;
_mcc.sig = 0;
stats.nil.was = (_gcc.raw && !(_mcc.raw));
stats.nil.not = (!(_gcc.raw) && _mcc.raw);
if ( stats.nil.was || stats.nil.not ) goto details_add;
stats.inf.was = (_gcc.exp != mcc.inf && _mcc.exp >= mcc.inf);
stats.inf.not = (_gcc.exp >= mcc.inf && _mcc.exp != mcc.inf);
if ( stats.inf.was || stats.inf.not ) goto details_put;
stats.inc.was = (gcc.raw == (mcc.raw - 1));
stats.inc.not = (gcc.raw == (mcc.raw + 1));
if ( stats.inc.was || stats.inc.not ) goto details_add;
stats.mul.was = (_gcc.exp == (_mcc.exp - 1));
stats.mul.not = (_gcc.exp == (_mcc.exp + 1));
if ( stats.mul.was || stats.mul.not ) goto details_add;
stats.shl.was = ((_gcc.man << 1) == _mcc.man);
stats.shl.not = (!(stats.shl.was) && _gcc.man == (_mcc.man << 1));
if ( stats.shl.was || stats.shl.not ) goto details_add;
details_put:
_gcc.raw = gcc.raw;
_mcc.raw = mcc.raw;
printf( "given %s\n", txt );
printf( "expect " FPN_PRIe ", " FPN_PRIf "\n", _gcc.fpn, _gcc.fpn );
printf( "result " FPN_PRIe ", " FPN_PRIf "\n", _mcc.fpn, _mcc.fpn );
printb( "gcc = ", &(gcc.raw), bitsof(gcc.raw), "\n" );
printb( "mcc = ", &(mcc.raw), bitsof(mcc.raw), "\n" );
printb( "gcc mantissa = ", &g, limits.man_bits, "\n" );
printb( "mcc mantissa = ", &m, limits.man_bits, "\n" );
g >>= limits.man_bits;
m >>= limits.man_bits;
printb( "gcc exponent = ", &g, limits.exp_bits, "\n" );
printb( "mcc exponent = ", &m, limits.exp_bits, "\n" );
g >>= limits.exp_bits;
m >>= limits.exp_bits;
printb( "gcc negative = ", &g, 1, "\n" );
printb( "mcc negative = ", &m, 1, "\n" );
printf( "tmp.base = %llu\n", (ullong)mcc.base );
printf( "tmp.neg = %llu\n", (ullong)(mcc.neg) );
printf( "tmp.num = %llu\n", (ullong)(mcc.num) );
printf( "tmp.fpn = %llu\n", (ullong)(mcc.fpn) );
printf( "tmp.one = %llu\n", (ullong)(mcc.one) );
printf( "tmp.tmp = %llu\n", (ullong)(mcc.tmp) );
printf( "tmp.pos = %ld\n", mcc.pos );
printf( "tmp.exp = %ld\n", mcc.exp );
printf( "gcc.pos = %ld\n", gcc.pos );
printf( "gcc.exp = %ld\n", gcc.exp );
details_add:
dst->count++;
dst->eql = waswasnot_add( dst->eql, stats.eql );
dst->nil = waswasnot_add( dst->nil, stats.nil );
dst->inc = waswasnot_add( dst->inc, stats.inc );
dst->shl = waswasnot_add( dst->shl, stats.shl );
dst->mul = waswasnot_add( dst->mul, stats.mul );
dst->inf = waswasnot_add( dst->inf, stats.inf );
}
mcc_big_t fill_big( mcc_fpn_t mcc,
mcc_big_t big, uchar *base, size_t perN ) {
size_t size = perN / 2;
big.limits = mcc.limits;
big.rounds = mcc.rounds;
big.epsilon = mcc.epsilon;
big.base = mcc_vint_wrap( 0, base, size );
big.inf = mcc_vint_wrap( 0, &(base[perN]), size );
big.neg = mcc_vint_wrap( 0, &(base[perN * 2]), size );
big.num = mcc_vint_wrap( 0, &(base[perN * 3]), size );
big.fpn = mcc_vint_wrap( 0, &(base[perN * 4]), size );
big.one = mcc_vint_wrap( 0, &(base[perN * 5]), size );
big.tmp = mcc_vint_wrap( 0, &(base[perN * 6]), size );
big.raw = mcc_vint_wrap( 0, &(base[perN * 7]), size );
return big;
}
int main() {
mcc_fpn_t gcc = {0}, mcc = {0}, tmp;
mcc_big_t big_gcc = {0}, big_mcc = {0}, big_tmp = {0};
mcc_fpn_limits_t limits = {0};
char txt[bitsof(double)] = {0};
int i, j, k, c = 36, e = c, f = c;
fpn_stats_t stats = {0}, big_stats = {0};
size_t size = 0;
uchar *addr = NULL;
mcc.one = 1;
mcc.base = 10;
limits.exp_bias = FPN_MAX_EXP;
limits.exp_bits = FPN_EXP_BIT;
limits.max_exp_digits = FPN_MAX_10_EXP;
limits.min_exp_digits = FPN_MIN_10_EXP;
limits.max_exp = FPN_MAX_EXP;
limits.min_exp = FPN_MIN_EXP;
limits.man_bits = FPN_MAN_BIT;
mcc.limits = limits;
mcc.rounds = FLT_ROUNDS;
mcc.epsilon = FLT_EPSILON;
mcc = mcc_fpn_set_inf( mcc );
printf("Numbers limited to: %d.%de+/-%d\n", c, f, e );
printf( "mcc.rounds = %ld\n", mcc.rounds );
printf( "mcc.epsilon = %ld\n", mcc.epsilon );
#if 0
printf( "limits.exp_bias = %ld\n", limits.exp_bias );
printf( "limits.exp_bits = %ld\n", limits.exp_bits );
printf( "limits.max_exp_digits = %ld\n", limits.max_exp_digits );
printf( "limits.min_exp_digits = %ld\n", limits.min_exp_digits );
printf( "limits.max_exp = %ld\n", limits.max_exp );
printf( "limits.min_exp = %ld\n", limits.min_exp );
printf( "limits.man_bits = %ld\n", limits.man_bits );
#endif
size = (limits.max_exp / CHAR_BIT) * 2;
addr = malloc( limits.max_exp * 4 );
if ( !addr ) return EXIT_FAILURE;
big_gcc = fill_big( mcc, big_gcc, addr, size );
big_mcc = fill_big( mcc, big_mcc, &(addr[size * 8]), size );
big_tmp = fill_big( mcc, big_tmp, &(addr[size * 16]), size );
for ( i = 0; i <= e; ++i ) {
for ( j = 0; j <= c; ++j ) {
for ( k = 0; k < f; ++k ) {
memset( txt, 0, bitsof(double) );
snprintf( txt, bitsof(double), "%d.%de%d", j, k, i );
tmp = mcc_fpn_read( txt, &gcc, mcc, mcc );
details( &stats, txt, gcc, tmp );
mcc_big_read( txt, &big_gcc, big_mcc, big_tmp );
gcc.raw = *((mcc_uhuge_t*)(big_gcc.raw.zero.seg));
tmp.raw = *((mcc_uhuge_t*)(big_mcc.raw.zero.seg));
details( &big_stats, txt, gcc, tmp );
memset( txt, 0, bitsof(double) );
snprintf( txt, bitsof(double), "%d.%de%d", j, k, -i );
tmp = mcc_fpn_read( txt, &gcc, mcc, mcc );
details( &stats, txt, gcc, tmp );
mcc_big_read( txt, &big_gcc, big_mcc, big_tmp );
gcc.raw = *((mcc_uhuge_t*)(big_gcc.raw.zero.seg));
tmp.raw = *((mcc_uhuge_t*)(big_mcc.raw.zero.seg));
details( &big_stats, txt, gcc, tmp );
}
}
}
fpn_stats_put( NULL, NULL, stats );
fpn_stats_put( "Big", NULL, big_stats );
free(addr);
return 0;
}
long mcc_geti( long c, int l, int h ) {
if ( c >= '0' && c <= '9' )
return c - '0';
else if ( c >= 'A' && c <= 'Z' )
return (c - 'A') + h;
else if ( c >= 'a' && c <= 'z' )
return (c - 'a') + l;
return -1;
}
mcc_fpn_t mcc_fpn_set_inf( mcc_fpn_t mcc ) {
mcc.inf = 0;
mcc.inf = ~(mcc.inf);
mcc.inf <<= mcc.limits.exp_bits;
mcc.inf = ~(mcc.inf);
return mcc;
}
mcc_fpn_t mcc_fpn_make( mcc_fpn_t mcc, mcc_fpn_t tmp ) {
mcc_fpn_limits_t limits = mcc.limits;
mcc.raw = 0;
tmp = mcc;
if ( tmp.pos > 0 || !(mcc.num) || !(mcc.one) ) goto mcc_fpn_sig;
if ( !(tmp.num % tmp.one) ) {
tmp.num /= tmp.one;
tmp.one = 1;
tmp.pos = 0;
}
while ( tmp.exp > 0 ) {
if ( tmp.pos == 0 || tmp.one == 1 ) break;
tmp.one /= tmp.base;
tmp.pos++;
tmp.exp--;
}
if ( tmp.exp > limits.max_exp || tmp.exp < limits.min_exp ) {
mcc_fpn_inf:
tmp.raw = mcc.inf;
goto mcc_fpn_exp;
}
for ( ; tmp.exp > 0; tmp.exp-- ) {
tmp.tmp = tmp.num;
tmp.num *= mcc.base;
if ( tmp.num <= tmp.tmp ) goto mcc_fpn_inf;
}
for ( ; tmp.exp < 0; tmp.exp++ ) {
tmp.tmp = tmp.one;
tmp.one *= mcc.base;
if ( tmp.one <= tmp.tmp ) goto mcc_fpn_sig;
}
tmp.fpn = tmp.num % tmp.one;
tmp.num /= tmp.one;
if ( !(tmp.fpn) ) tmp.one = 1;
tmp.pos = 0;
if ( tmp.num ) {
for ( tmp.tmp = tmp.num;
tmp.tmp > 1; tmp.pos++, tmp.tmp >>= 1 );
}
else {
for ( tmp.tmp = tmp.one
; tmp.tmp > tmp.fpn; tmp.pos--, tmp.tmp >>= 1 );
if ( tmp.tmp == tmp.fpn && tmp.pos < -1 ) tmp.pos--;
}
mcc.pos = tmp.pos;
tmp.raw = limits.exp_bias + (tmp.pos - 1);
if ( tmp.raw > mcc.inf ) goto mcc_fpn_inf;
if ( tmp.pos > limits.man_bits ) {
tmp.pos -= limits.man_bits;
tmp.fpn = 0;
tmp.fpn = ~(tmp.fpn);
tmp.fpn <<= tmp.pos;
tmp.fpn = ~(tmp.fpn);
tmp.fpn &= tmp.num;
tmp.one <<= tmp.pos;
mcc.raw = tmp.num >> tmp.pos;
tmp.tmp = tmp.one / 2;
if ( tmp.fpn > tmp.tmp ) mcc.raw++;
else if ( tmp.fpn == tmp.tmp ) {
switch ( mcc.rounds ) {
case 1: if ( mcc.raw & 1u ) mcc.raw++; break;
}
}
}
else {
mcc.raw = tmp.num;
tmp.tmp = tmp.fpn;
#if 0
if ( tmp.pos < -8 ) {
tmp.tmp <<= -(tmp.pos + 8);
mcc.raw <<= -(tmp.pos + 8);
tmp.pos = -8;
}
#endif
for ( ; tmp.pos < limits.man_bits; tmp.pos++ ) {
tmp.tmp *= 2;
mcc.raw <<= 1;
if ( tmp.tmp >= tmp.one ) {
mcc.raw |= 1;
tmp.tmp -= tmp.one;
}
}
tmp.tmp *= 2;
if ( tmp.tmp >= tmp.one ) mcc.raw++;
}
tmp.tmp = (bitsof(mcc.raw) - limits.man_bits);
mcc.raw <<= tmp.tmp;
mcc.raw >>= tmp.tmp;
mcc_fpn_exp:
tmp.raw <<= limits.man_bits;
mcc.raw |= tmp.raw;
mcc_fpn_sig:
tmp.neg <<= (limits.man_bits + limits.exp_bits);
mcc.raw |= tmp.neg;
mcc.num = tmp.num;
mcc.one = tmp.one;
mcc.fpn = tmp.fpn;
return mcc;
}
mcc_fpn_t mcc_fpn_read(
char *txt,
mcc_fpn_t *gcc,
mcc_fpn_t tmp,
mcc_fpn_t fpn
) {
char *text, sig;
int c = 0, l = 10, h = 10;
char e = 'e', E = 'E';
FPN_UNION lib = {0};
while ( isspace(*txt) ) ++txt;
text = txt;
switch ( *txt ) {
case '-': tmp.neg = 1;
case '+': ++txt;
}
if ( *txt == '0' ) {
++txt;
switch ( *txt ) {
case 'b': case 'B':
++txt;
tmp.base = 2;
break;
case 'x': case 'X':
++txt;
tmp.base = 16;
break;
}
if ( tmp.base > 36 )
l = 36;
}
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || c >= tmp.base ) break;
++txt;
tmp.num *= tmp.base;
tmp.num += c;
}
tmp.pos = 0;
if ( *txt == '.' ) {
++txt;
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || c >= tmp.base ) break;
++txt;
tmp.one *= tmp.base;
tmp.num *= tmp.base;
tmp.num += c;
tmp.pos--;
}
}
if ( *txt == e || *txt == E ) {
++txt;
switch ( *txt ) { case '-': case '+': sig = *txt; ++txt; }
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || c >= tmp.base ) break;
++txt;
tmp.exp *= tmp.base;
tmp.exp += c;
}
if ( sig == '-' ) tmp.exp = -(tmp.exp);
}
*gcc = tmp;
if ( tmp.base == 10 ) sscanf( text, FPN_SCNe, &(lib.fpn) );
else if ( tmp.base == 16 ) sscanf( text, FPN_SCNa, &(lib.fpn) );
gcc->raw = lib.raw;
fpn = tmp;
return mcc_fpn_make( fpn, tmp );
}
mcc_big_t mcc_big_set_inf( mcc_big_t big ) {
int ret = mcc_vint_validate( &(big.inf) );
mcc_fpn_limits_t limits = big.limits;
if ( ret != EXIT_SUCCESS ) {
printf( "Error: %08X, %s\n", ret, strerror(ret) );
}
memset( big.inf.zero.seg, ~0u, big.inf.size );
mcc___vint_op_shl( big.inf, limits.exp_bits );
mcc__vint_op_not( big.inf );
return big;
}
int mcc_big_validiate( mcc_big_t *mcc_big ) {
int ret;
if ( !mcc_big ) return EDESTADDRREQ;
ret = mcc_vint_validate( &(mcc_big->base) );
if ( ret != EXIT_SUCCESS ) return ret;
return EXIT_SUCCESS;
}
mcc_big_t mcc_big_make( mcc_big_t mcc, mcc_big_t tmp ) {
int ret = mcc_big_validiate(&mcc);
mcc_vint_seg_t bits = 0;
mcc_uhuge_t _one = 1, size, need;
mcc_uint_t one = {0};
mcc_fpn_limits_t limits = mcc.limits;
if ( ret != EXIT_SUCCESS ) {
printf("Error: %08X, %s\n", ret, strerror(ret) );
return mcc;
}
ret = mcc_big_validiate(&tmp);
if ( ret != EXIT_SUCCESS ) {
printf("Error: %08X, %s\n", ret, strerror(ret) );
return mcc;
}
need = ((limits.exp_bits + limits.man_bits + 1) / CHAR_BIT);
size = (limits.max_exp / CHAR_MAX) + 1;
if ( size <= (need * 4) || tmp.pos > 0
|| mcc__vint_is_nil(mcc.num)
|| mcc__vint_is_nil(mcc.one)
|| tmp.raw.size < need || tmp.inf.size < need
|| tmp.neg.size < need || tmp.fpn.size < size
|| tmp.num.size < size || tmp.one.size < size
|| tmp.tmp.size < size || tmp.base.size < size
|| mcc.raw.size < need || mcc.inf.size < need
|| mcc.neg.size < need || mcc.fpn.size < size
|| mcc.num.size < size || mcc.one.size < size
|| mcc.tmp.size < size || mcc.base.size < size )
goto mcc_big_sig;
one = mcc_vint_wrap( 0, &_one, sizeof(_one) );
mcc_vint_fill( tmp.tmp, tmp.num );
mcc___vint_op_div( tmp.tmp, tmp.one, tmp.fpn );
if ( mcc__vint_is_nil( mcc.fpn ) ) {
(void)mcc_vint_fill( tmp.num, tmp.tmp );
(void)mcc_vint_fill( tmp.one, one );
tmp.pos = 0;
}
while ( tmp.exp > 0 ) {
if ( tmp.pos == 0 || mcc__vint_is_eql( tmp.one, one ) )
break;
(void)mcc___vint_op_div( tmp.one, tmp.base, tmp.tmp );
tmp.pos++;
tmp.exp--;
}
if ( tmp.exp > limits.max_exp || tmp.exp < limits.min_exp ) {
mcc_big_inf:
mcc_vint_fill( tmp.raw, mcc.inf );
goto mcc_big_exp;
}
for ( ; tmp.exp > 0; tmp.exp-- ) {
if ( mcc___vint_op_mul( tmp.num, tmp.base, tmp.tmp ) ==
EOVERFLOW ) goto mcc_big_inf;
}
for ( ; tmp.exp < 0; tmp.exp++ ) {
if ( mcc___vint_op_mul( tmp.one, tmp.base, tmp.tmp ) ==
EOVERFLOW ) goto mcc_big_sig;
}
(void)mcc___vint_op_div( tmp.num, tmp.one, tmp.fpn );
if ( mcc__vint_is_nil( tmp.fpn ) ) mcc_vint_fill( tmp.one, one );
tmp.pos = 0;
if ( mcc__vint_is_gte( tmp.num, one ) ) {
for (
mcc_vint_fill( tmp.tmp, tmp.num );
mcc__vint_is_gth( tmp.tmp, one );
tmp.pos++, mcc___vint_op_shr( tmp.tmp, 1 )
);
}
else {
for (
mcc_vint_fill( tmp.tmp, tmp.one );
mcc__vint_is_gth( tmp.tmp, tmp.fpn );
tmp.pos--, mcc___vint_op_shr( tmp.tmp, 1 )
);
if ( mcc__vint_is_eql( tmp.tmp, tmp.fpn ) ) tmp.pos--;
}
mcc.pos = tmp.pos;
mcc_vint_fill(
tmp.raw, mcc_vint_wrap(
1, &(limits.exp_bias), sizeof(limits.exp_bias) ) );
if ( mcc__vint_is_gth( tmp.raw, mcc.inf ) ) goto mcc_big_inf;
if ( tmp.pos > limits.man_bits ) {
tmp.pos -= limits.man_bits;
mcc__vint_op_xor( tmp.fpn, tmp.fpn );
mcc__vint_op_not( tmp.fpn );
mcc___vint_op_shl( tmp.fpn, tmp.pos );
mcc__vint_op_not( tmp.fpn );
mcc__vint_op_and( tmp.fpn, tmp.num );
mcc___vint_op_shl( tmp.one, tmp.pos );
mcc_vint_fill( tmp.tmp, tmp.num );
mcc___vint_op_shr( tmp.tmp, tmp.pos );
mcc_vint_fill( mcc.raw, tmp.tmp );
mcc_vint_fill( tmp.tmp, tmp.one );
mcc___vint_op_shr( tmp.tmp, 1 );
ret = mcc__vint_op_cmp( tmp.fpn, tmp.tmp );
if ( ret > 0 ) mcc__vint_op_inc( mcc.raw );
else if ( ret == 0 ) {
switch ( mcc.rounds ) {
case 1:
if ( *(mcc.raw.zero.seg) & mcc.raw.zero.bit )
mcc__vint_op_inc( mcc.raw );
break;
}
}
}
else {
mcc_vint_fill( mcc.raw, tmp.num );
mcc_vint_fill( tmp.tmp, tmp.fpn );
for ( ; tmp.pos < limits.man_bits; tmp.pos++ ) {
bits++;
mcc___vint_op_shl( tmp.tmp, 1 );
if ( mcc__vint_is_gte( tmp.tmp, tmp.one ) ) {
(void)mcc__vint_op_sub( tmp.tmp, tmp.one );
(void)mcc___vint_op_shl( tmp.num, bits );
*(tmp.num.zero.seg) |= tmp.num.zero.bit;
bits = 0;
}
}
if ( bits ) (void)mcc___vint_op_shl( tmp.num, bits );
}
bits = (mcc.raw.stop.b - mcc.raw.zero.b) - limits.man_bits;
mcc___vint_op_shl( mcc.raw, bits );
mcc___vint_op_shr( mcc.raw, bits );
mcc_big_exp:
mcc___vint_op_shl( tmp.raw, limits.exp_bits );
mcc__vint_op_aor( mcc.raw, tmp.raw );
mcc_big_sig:
mcc___vint_op_shl( tmp.neg, limits.man_bits + limits.exp_bits );
return mcc;
}
mcc_big_t mcc_big_read(
char *txt,
mcc_big_t *gcc,
mcc_big_t tmp,
mcc_big_t big
) {
char *text, sig;
int c = 0, l = 10, h = 10;
char e = 'e', E = 'E';
FPN_UNION lib = {0};
mcc__vint_t C = mcc_vint_wrap( 1, &c, sizeof(c) );
while ( isspace(*txt) ) ++txt;
text = txt;
(void)mcc__vint_op_xor( tmp.neg, tmp.neg );
switch ( *txt ) {
case '-': *(tmp.neg.zero.seg) = tmp.neg.zero.bit;
case '+': ++txt;
}
if ( *txt == '0' ) {
++txt;
switch ( *txt ) {
case 'b': case 'B':
++txt;
c = 2;
mcc_vint_fill( tmp.base, C );
break;
case 'x': case 'X':
++txt;
c = 16;
mcc_vint_fill( tmp.base, C );
break;
}
c = 36;
if ( mcc__vint_is_gth( tmp.base, C ) )
l = 36;
}
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || mcc__vint_is_gte( C, tmp.base ) ) break;
++txt;
if ( mcc___vint_op_mul( tmp.num, tmp.base, tmp.tmp )
== EOVERFLOW ) {
(void)mcc_vint_fill( big.raw, big.neg );
(void)mcc___vint_op_shl( big.raw, big.limits.exp_bits );
(void)mcc__vint_op_aor( big.raw, big.inf );
(void)mcc___vint_op_shl( big.raw, big.limits.man_bits );
return big;
}
(void)mcc__vint_op_add( tmp.num, C );
}
tmp.pos = 0;
if ( *txt == '.' ) {
++txt;
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || mcc__vint_is_gte( C, tmp.base ) ) break;
++txt;
if ( mcc___vint_op_mul( tmp.num, tmp.base, tmp.tmp )
== EOVERFLOW ) {
(void)mcc_vint_fill( big.raw, big.neg );
(void)mcc___vint_op_shl( big.raw, big.limits.exp_bits );
(void)mcc___vint_op_shl( big.raw, big.limits.man_bits );
return big;
}
(void)mcc__vint_op_add( tmp.num, C );
(void)mcc___vint_op_mul( tmp.one, tmp.base, tmp.tmp );
tmp.pos--;
}
}
if ( *txt == e || *txt == E ) {
++txt;
switch ( *txt ) { case '-': case '+': sig = *txt; ++txt; }
while ( *txt ) {
c = mcc_geti( *txt, l, h );
if ( c < 0 || mcc__vint_is_gte( C, tmp.base ) ) break;
++txt;
tmp.exp *= *(tmp.base.zero.seg);
tmp.exp += c;
}
if ( sig == '-' ) tmp.exp = -(tmp.exp);
}
*gcc = tmp;
mcc_vint_fill( gcc->inf, tmp.inf );
mcc_vint_fill( gcc->num, tmp.num );
mcc_vint_fill( gcc->fpn, tmp.fpn );
mcc_vint_fill( gcc->one, tmp.one );
mcc_vint_fill( C, tmp.base );
if ( c == 10 ) sscanf( text, FPN_SCNe, &(lib.fpn) );
else if ( c == 16 ) sscanf( text, FPN_SCNa, &(lib.fpn) );
mcc_vint_to_val( gcc->raw, lib.raw );
mcc_vint_fill( big.inf, tmp.inf );
mcc_vint_fill( big.num, tmp.num );
mcc_vint_fill( big.fpn, tmp.fpn );
mcc_vint_fill( big.one, tmp.one );
return mcc_big_make( big, tmp );
}
#include <limits.h>
#include <inttypes.h>
#include "mcc_vint.h"
mcc_bit_t mcc_bit_op_inc( mcc_bit_t num ) {
mcc_vint_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_vint_seg_t bits ) {
#ifdef MCC_BIT_SLOW
while ( bits-- ) {
num = mcc_bit_op_inc(num);
if ( !(num.bit) ) return num;
}
return num;
#else
mcc_vint_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_vint_seg_t bits ) {
#ifdef MCC_BIT_SLOW
while ( bits-- ) {
num = mcc_bit_op_dec(num);
if ( !(num.bit) ) return num;
}
return num;
#else
mcc_vint_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
int mcc_vint_validate( mcc__vint_t *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_vint_validate2( mcc__vint_t *num, mcc__vint_t *val ) {
int ret = mcc_vint_validate( num );
switch ( ret ) {
case EXIT_SUCCESS: break;
case EADDRNOTAVAIL: return EDESTADDRREQ;
default: return ret;
}
return mcc_vint_validate( val );
}
int mcc_vint_validate3( mcc__vint_t *num, mcc__vint_t *val, mcc__vint_t *var ) {
int ret = mcc_vint_validate2( num, val );
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc_vint_validate(var);
if ( ret != EXIT_SUCCESS )
return (ret == EADDRNOTAVAIL) ? EDESTADDRREQ : ret;
if ( var->size < num->size ) return ERANGE;
return EXIT_SUCCESS;
}
void mcc_vint_print( mcc__vint_t num, mcc_vint_seg_t min ) {
int ret = mcc_vint_validate(&num);
mcc_vint_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) );
}
}
mcc__vint_t mcc_vint_wrap( bool has_sign, void *addr, size_t size ) {
mcc__vint_t tmp = {0};
if ( !addr || !size ) return tmp;
tmp.size = size;
tmp.zero.seg = addr;
tmp.zero.bit = 1;
tmp.stop = mcc__bit_op_add( tmp.zero, size * CHAR_BIT );
if ( has_sign ) tmp.sign = mcc_bit_op_dec( tmp.stop );
return tmp;
}
int mcc_vint_size( mcc__vint_t *num, size_t size ) {
mcc_vint_seg_t *mem;
size_t nodes;
if ( !size ) {
if ( num->zero.seg ) free( num->zero.seg );
memset( num, 0, sizeof(mcc__vint_t) );
return EXIT_SUCCESS;
}
nodes = size / sizeof(mcc_vint_seg_t);
if ( size % sizeof(mcc_vint_seg_t) ) ++nodes;
size = nodes * sizeof(mcc_vint_seg_t);
if ( !(num->zero.seg) ) mem = malloc( size );
else mem = realloc( num->zero.seg, size );
if ( !mem ) ENOMEM;
(void)memset( &(num->zero), 0, sizeof(mcc_bit_t) );
num->zero.seg = mem;
num->zero.bit = 1;
num->size = size;
num->stop = mcc__bit_op_add( num->zero, size * CHAR_BIT );
return EXIT_SUCCESS;
}
int mcc__vint_get_sign( mcc_vint_t num ) {
if ( num.sign.seg )
return (*(num.sign.seg) & num.sign.bit) ? 1 : 0;
return -1;
}
int mcc_vint_fill( mcc__vint_t num, mcc__vint_t val ) {
(void)mcc__vint_op_xor( num, num );
if ( mcc__vint_get_sign(val) == 1 ) {
(void)mcc__vint_op_not( num );
return mcc__vint_op_and( num, val );
}
return mcc__vint_op_aor( num, val );
}
int mcc_vint_size_and_fill( mcc__vint_t *num, mcc__vint_t val ) {
int ret = mcc_vint_size( num, val.size );
if ( ret != EXIT_SUCCESS ) return ret;
return mcc_vint_fill( *num, val );
}
int mcc__vint_op_cmp( mcc__vint_t num, mcc__vint_t val ) {
mcc_bit_t n = {0}, v = {0};
mcc_vint_seg_t nb = 0, vb = 0;
int nn0 = 0, vn0 = 0;
if ( mcc_vint_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_vint_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;
}
int biclamp1( mcc__vint_t num ) {
int ret = mcc_vint_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__vint_t num ) {
int ret = mcc_vint_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__vint_op_not( mcc__vint_t num ) {
int ret = mcc_vint_validate( &num );
mcc_bit_t n;
if ( ret != EXIT_SUCCESS ) return ret;
n = num.zero;
while ( n.b < num.stop.b ) {
*(n.seg) ^= n.bit;
n = mcc_bit_op_inc(n);
}
return EXIT_SUCCESS;
}
int mcc__vint_op_aor( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_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__vint_op_xor( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_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__vint_op_and( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_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___vint_op_shl( mcc__vint_t num, mcc_vint_seg_t bits ) {
int ret = mcc_vint_validate( &num );
mcc_bit_t n, v;
mcc_vint_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 > num.zero.b ) {
n = mcc_bit_op_dec(n);
if ( *(n.seg) & n.bit ) {
*(n.seg) ^= n.bit;
ret = EOVERFLOW;
}
}
return ret;
}
int mcc___vint_op_shr( mcc__vint_t num, mcc_vint_seg_t bits ) {
int ret = mcc_vint_validate( &num );
mcc_bit_t n, v;
mcc_vint_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.b < num.stop.b ) {
if ( *(n.seg) & n.bit ) {
ret = EOVERFLOW;
*(n.seg) ^= n.bit;
}
n = mcc_bit_op_inc(n);
}
return ret;
}
int mcc__vint_op_inc( mcc__vint_t num ) {
mcc_bit_t n;
_Bool c = 1;
int ret = mcc_vint_validate( &num );
if ( ret != EXIT_SUCCESS ) return ret;
n = num.zero;
for ( ; n.b < num.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 mcc__vint_op_add( mcc__vint_t num, mcc__vint_t val ) {
mcc_bit_t n, v, stop;
mcc_vint_seg_t b = 0, bits, nb, vb;
_Bool c = 0;
int ret = mcc_vint_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__vint_t num, mcc__vint_t val ) {
int ret = mcc__vint_op_add( num, val );
if ( ret == EOVERFLOW ) {
memset( num.zero.seg, -1, num.size );
ret = biclamp0( num );
}
return ret;
}
int add_int( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t tmp;
if ( ret != EXIT_SUCCESS ) return ret;
tmp = num;
tmp.stop = mcc_bit_op_dec(tmp.stop);
ret = mcc__vint_op_add( tmp, val );
if ( ret == EOVERFLOW ) {
memset( num.zero.seg, -1, num.size );
ret = biclamp0( tmp );
}
return ret;
}
int mcc__vint_op_dec( mcc__vint_t num ) {
mcc_bit_t n;
_Bool c = 1;
int ret = mcc_vint_validate( &num );
if ( ret != EXIT_SUCCESS ) return ret;
n = num.zero;
for ( ; n.b < num.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 mcc__vint_op_sub( mcc__vint_t num, mcc__vint_t val ) {
mcc_bit_t n, v, s;
_Bool c = 0;
mcc_vint_seg_t b = 0, bits = 0, nb, vb;
int ret = mcc_vint_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___vint_op_mul( mcc__vint_t num, mcc__vint_t val, mcc__vint_t tmp ) {
int ret = mcc_vint_validate3( &num, &val, &tmp );
mcc_bit_t v, s;
mcc_vint_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___vint_op_shl( tmp, bits );
if ( mcc__vint_op_add( num, tmp ) == EOVERFLOW )
ret = EOVERFLOW;
bits = 0;
}
++bits;
}
return ret;
}
int mcc__vint_op_mul( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t tmp = {0};
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc_vint_size_and_fill( &tmp, num );
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc___vint_op_mul( num, val, tmp );
(void)mcc_vint_size( &tmp, 0 );
return ret;
}
int mcc___vint_op_div( mcc__vint_t num, mcc__vint_t val, mcc__vint_t rem ) {
int ret = mcc_vint_validate3( &num, &val, &rem );
mcc__vint_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 ( mcc__vint_is_nil( val ) ) return EXIT_SUCCESS;
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__vint_is_gte( rem, tmp ) ) {
seg.zero = mcc_bit_op_dec(seg.zero);
quo = mcc_bit_op_dec( quo );
if ( mcc__vint_is_gte( seg, tmp ) ) {
if ( mcc__vint_op_sub( seg, tmp ) == EOVERFLOW )
ret = EOVERFLOW;
*(quo.seg) |= quo.bit;
}
}
return ret;
}
int mcc__vint_op_div( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t rem = {0};
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc_vint_size( &rem, num.size );
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc___vint_op_div( num, val, rem );
(void)mcc_vint_size( &rem, 0 );
return ret;
}
int mcc__vint_op_mod( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t rem = {0};
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc_vint_size( &rem, num.size );
if ( ret != EXIT_SUCCESS ) return ret;
ret = mcc___vint_op_div( num, val, rem );
(void)memcpy( num.zero.seg, rem.zero.seg, num.size );
(void)mcc_vint_size( &rem, 0 );
return ret;
}
int mcc__vint_op_shl( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t tmp = {0}, cpy = {0};
mcc_vint_seg_t move = 0, bits = 0;
if ( ret != EXIT_SUCCESS ) return ret;
bits = num.stop.b - num.zero.b;
tmp = mcc_vint_wrap( 0, &bits, sizeof(bits) );
move = *(val.zero.seg);
if ( mcc__vint_is_gte( val, tmp ) ) {
ret = mcc_vint_size_and_fill( &cpy, val );
if ( ret != EXIT_SUCCESS ) return ret;
mcc___vint_op_shl( cpy, bits );
mcc___vint_op_shr( cpy, bits );
mcc_vint_size( &cpy, 0 );
if ( ret != EXIT_SUCCESS ) return ret;
}
return mcc___vint_op_shl(num, move );
}
int mcc__vint_op_shr( mcc__vint_t num, mcc__vint_t val ) {
int ret = mcc_vint_validate2( &num, &val );
mcc__vint_t tmp = {0}, cpy = {0};
mcc_vint_seg_t move = 0, bits = 0;
if ( ret != EXIT_SUCCESS ) return ret;
bits = num.stop.b - num.zero.b;
tmp = mcc_vint_wrap( 0, &bits, sizeof(bits) );
move = *(val.zero.seg);
if ( mcc__vint_is_gte( val, tmp ) ) {
ret = mcc_vint_size_and_fill( &cpy, val );
if ( ret != EXIT_SUCCESS ) return ret;
mcc___vint_op_shl( cpy, bits );
mcc___vint_op_shr( cpy, bits );
mcc_vint_size( &cpy, 0 );
if ( ret != EXIT_SUCCESS ) return ret;
}
return mcc___vint_op_shr( num, move );
}
#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__vint_t _num = {0}, _val = {0}, _rem = {0};
(void)mcc_vint_size_and_fill( &_num, &num, sizeof(num) );
(void)mcc_vint_size_and_fill( &_val, &val, sizeof(num) );
(void)mcc_vint_size_and_fill( &_rem, &num, sizeof(num) );
switch ( *op ) {
case 0: ret = EILSEQ; goto fail;
case '~': num = ~num; mcc__vint_op_not( &_num ); goto done;
case '|': num |= val; mcc__vint_op_aor( &_num, &_val ); goto done;
case '^': num ^= val; mcc__vint_op_xor( &_num, &_val ); goto done;
case '&': num &= val; mcc__vint_op_and( &_num, &_val ); goto done;
case '+':
if ( op[1] == '+' )
{ num++; mcc__vint_op_inc( &_num ); }
else
{ num += val; mcc__vint_op_add( &_num, &_val ); }
goto done;
case '*': num *= val; mcc__vint_op_mul( &_num, &_val ); goto done;
case '-':
if ( op[1] == '+' )
{ num--; mcc__vint_op_dec( &_num ); }
else
{ num -= val; mcc__vint_op_sub( &_num, &_val ); }
goto done;
case '/':
if ( val ) { rem %= val; num /= val; }
else { rem = num; num = 0; }
mcc___vint_op_div( &_num, &_val, &_rem );
goto done;
case '%':
if ( val ) { rem %= val; num = rem; }
else { rem = num; }
mcc___vint_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__vint_to_num( &_num, mcc__vint_is_eql( &_num, &_val ) );
goto done;
case '!':
if ( op[1] == '\0' ) {
num = !num;
mcc__vint_to_num( &_num, mcc__vint_is_nil( &_num ) );
}
else if ( op[1] == '=' ) {
num = (num != val);
mcc__vint_to_num( &_num, mcc__vint_is_neq( &_num, &_val ) );
}
goto done;
case '>':
if ( op[1] == '>' ) {
num >>= val;
mcc__vint_op_shr( &_num, &_val );
}
else if ( op[1] == '=' ) {
num = (num >= val);
mcc__vint_to_num( &_num, mcc__vint_is_gte( &_num, &_val ) );
}
else {
num = (num > val);
mcc__vint_to_num( &_num, mcc__vint_is_gth( &_num, &_val ) );
}
goto done;
case '<':
if ( op[1] == '<' ) {
num <<= val;
mcc__vint_op_shl( &_num, &_val );
}
else if ( op[1] == '=' ) {
num = (num <= val);
mcc__vint_to_num( &_num, mcc__vint_is_lte( &_num, &_val ) );
}
else {
num = (num < val);
mcc__vint_to_num( &_num, mcc__vint_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_vint_size( &_num, 0 );
mcc_vint_size( &_val, 0 );
mcc_vint_size( &_rem, 0 );
return ret;
}
#endif
#ifndef INC_MCC_FPN_H
#define INC_MCC_FPN_H
#include <float.h>
#include "mcc_vint.h"
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_PRIa "%ha"
#define HALF_PRIf "%hf"
#define HALF_PRIe "%he"
#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_PRIa "%a"
#define FLT_PRIf "%f"
#define FLT_PRIe "%e"
#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_PRIa "%la"
#define DBL_PRIf "%lf"
#define DBL_PRIe "%le"
#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_PRIa "%lla"
#define LDBL_PRIf "%llf"
#define LDBL_PRIe "%lle"
#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_PRIa FPN_PFX(PRIa)
#define FPN_PRIf FPN_PFX(PRIf)
#define FPN_PRIe FPN_PFX(PRIe)
#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_fpn_limits {
ulong exp_bias;
long man_bits;
long exp_bits;
long max_exp;
long min_exp;
long max_exp_digits;
long min_exp_digits;
} mcc_fpn_limits_t;
typedef struct mcc_fpn {
long rounds;
long epsilon;
long pos;
long exp;
mcc_uhuge_t base;
mcc_uhuge_t inf;
mcc_uhuge_t neg;
mcc_uhuge_t num;
mcc_uhuge_t fpn;
mcc_uhuge_t one;
mcc_uhuge_t tmp;
mcc_uhuge_t raw;
mcc_fpn_limits_t limits;
} mcc_fpn_t;
typedef struct mcc_big {
long rounds;
long epsilon;
long pos;
long exp;
mcc_uint_t inf;
mcc_uint_t base;
mcc_uint_t neg;
mcc_uint_t num;
mcc_uint_t fpn;
mcc_uint_t one;
mcc_uint_t tmp;
mcc_uint_t raw;
mcc_fpn_limits_t limits;
} mcc_big_t;
#endif
#ifndef INC_MCC_VINT_H
#define INC_MCC_VINT_H
#include <limits.h>
#include <inttypes.h>
#include <stdbool.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))
#define INC_BITMATH
#define MCC__INT_USE_HUGE
typedef unsigned int mcc_test_t;
#define MCC_TEST_END_BIT (~(UINT_MAX >> 1))
#define MCC_TEST_PRI_PFX ""
#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_vint_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_vint_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_vint_seg_t;
#define MCC__INT_SEG_END_BIT (~((~((unsigned __int128)0u)) >> 1))
#define MCC__INT_SEG_PRI_PFX "I128"
#else
typedef unsigned long mcc_vint_seg_t;
#define MCC__INT_SEG_END_BIT (~(ULONG_MAX >> 1))
#define MCC__INT_SEG_PRI_PFX "l"
#endif
typedef struct mcc_bit {
mcc_vint_seg_t i;
mcc_vint_seg_t *seg;
mcc_vint_seg_t b;
mcc_vint_seg_t bit;
} mcc_bit_t;
int mcc_bit_op_cmp( mcc_bit_t num, mcc_bit_t val );
mcc_bit_t mcc_bit_op_inc( mcc_bit_t num );
mcc_bit_t mcc_bit_op_dec( mcc_bit_t num );
mcc_bit_t mcc__bit_op_add( mcc_bit_t num, mcc_vint_seg_t bits );
mcc_bit_t mcc__bit_op_sub( mcc_bit_t num, mcc_vint_seg_t bits );
mcc_bit_t mcc_bit_op_dec_for_bit( mcc_bit_t stop, mcc_bit_t zero );
typedef struct mcc__vint {
int exit;
size_t size;
mcc_bit_t zero, stop, sign;
} mcc__vint_t, mcc_vint_t, mcc_uint_t;
int mcc__vint_get_sign( mcc__vint_t num );
int mcc_vint_validate( mcc__vint_t *num );
int mcc_vint_validate2( mcc__vint_t *num, mcc__vint_t *val );
int mcc_vint_validate3( mcc__vint_t *num, mcc__vint_t *val, mcc__vint_t *var );
void mcc_vint_print( mcc__vint_t num, mcc_vint_seg_t min );
mcc__vint_t mcc_vint_wrap( bool has_sign, void *addr, size_t size );
int mcc_vint_size( mcc__vint_t *num, size_t size );
int mcc_vint_fill( mcc__vint_t num, mcc__vint_t val );
#define mcc_vint_to_val( NUM, VAL ) \
mcc_vint_fill( (NUM), mcc_vint_wrap( -(-(VAL) < 0), &(VAL), sizeof(VAL) ) )
int mcc_vint_size_and_fill( mcc__vint_t *num, mcc__vint_t val );
int mcc__vint_op_cmp( mcc__vint_t num, mcc__vint_t val );
#define mcc__vint_is_nil( num ) (mcc__vint_op_cmp( num, (mcc__vint_t){0} ) == 0)
#define mcc__vint_is_eql( num, val ) (mcc__vint_op_cmp( num, val ) == 0)
#define mcc__vint_is_neq( num, val ) (mcc__vint_op_cmp( num, val ) != 0)
#define mcc__vint_is_gth( num, val ) (mcc__vint_op_cmp( num, val ) > 0)
#define mcc__vint_is_gte( num, val ) (mcc__vint_op_cmp( num, val ) >= 0)
#define mcc__vint_is_lth( num, val ) (mcc__vint_op_cmp( num, val ) < 0)
#define mcc__vint_is_lte( num, val ) (mcc__vint_op_cmp( num, val ) <= 0)
int mcc__vint_op_not( mcc__vint_t num );
int mcc__vint_op_inc( mcc__vint_t num );
int mcc__vint_op_dec( mcc__vint_t num );
int mcc__vint_op_aor( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_xor( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_and( mcc__vint_t num, mcc__vint_t val );
int mcc___vint_op_shl( mcc__vint_t num, mcc_vint_seg_t bits );
int mcc___vint_op_shr( mcc__vint_t num, mcc_vint_seg_t bits );
int mcc__vint_op_shl( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_shr( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_add( mcc__vint_t num, mcc__vint_t val );
int mcc___vint_op_mul( mcc__vint_t num, mcc__vint_t val, mcc__vint_t tmp );
int mcc__vint_op_mul( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_sub( mcc__vint_t num, mcc__vint_t val );
int mcc___vint_op_div( mcc__vint_t num, mcc__vint_t val, mcc__vint_t rem );
int mcc__vint_op_div( mcc__vint_t num, mcc__vint_t val );
int mcc__vint_op_mod( mcc__vint_t num, mcc__vint_t val );
#endif