/*
*/
#include <limits.h>
#include <inttypes.h>
#include <float.h>
#include <string.h>
#include <stdio.h>
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;
#define bitsof(T) (CHAR_BIT * sizeof(T))
#define HALF_MAN_BIT 10
#define HALF_EXP_BIT 5
#define LDBL_MAN_BIT 52
#define LDBL_EXP_BIT 37
#define FLT_SCNa "%a"
#define FLT_SCNf "%f"
#define FLT_SCNe "%e"
#define FLT_MAN_BIT 23
#define FLT_EXP_BIT 8
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 52
#define DBL_EXP_BIT 11
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 FPN_PFX(VAL) DBL##_##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_MAN_BIT FPN_PFX(MAN_BIT)
#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)
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;
ulong exp_bias;
ulong base;
mcc_uhuge_t raw;
} mcc_flexable_fpn_t;
mcc_flexable_fpn_t fpn_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;
}
}
_Bool check(
char *text, FPN_UNION gcc, FPN_UNION mcc, mcc_flexable_fpn_t flex ) {
_Bool same = (gcc.raw == mcc.raw);
if ( !same ) {
printf("negative %llu\n", (ullong)flex.negative );
printb( "gcc = ", &gcc, bitsof(mcc_uhuge_t) );
putchar('\n');
printb( "mcc = ", &mcc, bitsof(mcc_uhuge_t) );
putchar('\n');
printf ("fpn t = " FPN_SCNe " m = " FPN_SCNe "\n",
gcc.fpn, mcc.fpn );
printf ("value '%s'", text );
}
return !same;
}
void exponent( mcc_flexable_fpn_t flex, size_t limit ) {
mcc_flexable_fpn_t temp;
FPN_UNION gcc = {0}, mcc = {0};
size_t i, wrong, j = 0, total = 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);
flex.one = 1;
flex.base = 10;
wrong = 0;
for ( i = 0; i < limit; ++i ) {
gcc.fpn = i;
temp = flex;
temp.num = i;
temp = fpn_make(temp);
mcc.raw = temp.raw;
snprintf(text,128,"%zu%s",i,etxt);
wrong += check( text, gcc, mcc, temp );
putchar('\n');
}
j += i; total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
wrong = 0;
for ( i = 1; i < limit; ++i ) {
temp = flex;
temp.fpn = i;
while ( !(temp.fpn % temp.base) ) temp.fpn /= temp.base;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
snprintf(text,128,"0.%llu%s",(ullong)(temp.fpn),etxt);
temp = fpn_make(temp);
mcc.raw = temp.raw;
sscanf(text,FPN_SCNf,&(gcc.fpn));
wrong += check( text, gcc, mcc, temp );
putchar('\n');
}
j += i; total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
wrong = 0;
for ( i = 1; i < limit; ++i ) {
temp = flex;
temp.num = i;
temp.fpn = i;
while ( !(temp.fpn % temp.base) ) temp.fpn /= temp.base;
while ( temp.one <= temp.fpn ) temp.one *= temp.base;
snprintf(text,128,"%zu.%llu%s",i,(ullong)(temp.fpn),etxt);
temp = fpn_make(temp);
mcc.raw = temp.raw;
sscanf(text,FPN_SCNf,&(gcc.fpn));
wrong += check( text, gcc, mcc, temp );
putchar('\n');
}
j += i; total += wrong;
if ( wrong ) printf( "Tried = %zu, Wrong = %zu\n", i, wrong );
if ( total ) printf( "Total Tried = %zu, Total Wrong = %zu\n", j, total );
}
int main ()
{
size_t i = 0, limit = 25;
#if 1
size_t wrong = 0;
FPN_UNION gcc, mcc;
#endif
mcc_flexable_fpn_t flex = {0}, temp;
flex.exp_bias = FPN_MAX_EXP;
flex.exp_bits = FPN_EXP_BIT;
flex.max_exp_digits = FPN_MAX_10_EXP;
flex.max_exp = FPN_MAX_EXP;
flex.min_exp = FPN_MIN_EXP;
flex.man_bits = FPN_MAN_BIT;
temp = flex;
for ( i = 0; i <= limit; ++i ) {
temp.exp = i;
exponent( flex, limit );
temp.exp = -(temp.exp);
}
#if 1
for ( i = 0; fpn_text[i] && i < 100; ++i ) {
temp = fpn_read (fpn_text[i], &gcc, flex);
mcc.raw = temp.raw;
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.exp >= temp.max_exp_digits ) {
flex.raw = ~0;
flex.raw >>= (bitsof(mcc_uhuge_t) - temp.exp_bits);
flex.raw <<= temp.man_bits;
flex.raw |= temp.negative;
return flex;
}
if ( (temp.exp <= -temp.max_exp_digits) ||
(!(temp.num) && !(temp.fpn)) ) {
flex.raw = temp.negative;
return flex;
}
/* Preserve exponent in case we need it later */
pos = temp.exp;
while ( pos > 0 ) {
temp.num *= temp.base;
temp.fpn *= temp.base;
if ( temp.fpn >= temp.one ) {
NUM = temp.fpn / temp.one;
temp.fpn -= NUM * temp.one;
temp.num += NUM;
}
--pos;
}
while ( pos < 0 ) {
NUM = temp.num % temp.base;
temp.fpn += NUM * temp.one;
temp.one *= temp.base;
temp.num /= temp.base;
++pos;
}
/* Calculate normal exponent */
if ( temp.num ) {
if ( !temp.fpn )
for ( ; temp.num && !(temp.num % temp.base); temp.raw++, temp.num >>= 1 );
for ( NUM = temp.num, pos = 0; NUM > 1; ++pos, NUM >>= 1 );
}
else for ( NUM = temp.fpn, pos = 0; NUM && NUM < temp.one; --pos, NUM <<= 1 );
/* Set exponent and mantissa */
flex.raw = temp.num;
temp.raw += temp.exp_bias + pos - 1;
if ( pos > pos_max ) {
pos_max = pos - pos_max;
++(temp.num);
flex.raw = temp.num >> pos_max;
}
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;
return flex;
}
mcc_flexable_fpn_t fpn_read (
char *text, FPN_UNION *gcc, mcc_flexable_fpn_t flex )
{
char *_text = text;
ulong c;
gcc->raw = 0;
flex.base = 10;
flex.negative = (*text == '-');
if ( flex.negative || *text == '+' )
++text;
if ( *text =='0' ) {
++text;
if ( *text == 'x' || *text == 'X' ) {
flex.base = 16;
++text;
}
}
if ( flex.base == 10 )
sscanf (_text, FPN_SCNf, &(gcc->fpn));
else
sscanf (_text, FPN_SCNa, &(gcc->fpn));
while (*text == '0')
++text;
for (; *text; ++text)
{
if ( *text >= '0' && *text <= '9' )
c = *text - '0';
else if ( *text >= 'A' && *text <= 'F' )
c = 10 + ( *text - 'A' );
else if ( *text >= 'a' && *text <= 'f' )
c = 10 + ( *text - 'a' );
else break;
if ( c >= flex.base ) break;
flex.num *= flex.base;
flex.num += c;
}
flex.one = 1;
flex.fpn = 0;
if (*text == '.')
{
for (++text; *text; ++text)
{
if ( *text >= '0' && *text <= '9' )
c = *text - '0';
else if ( *text >= 'A' && *text <= 'F' )
c = 10 + ( *text - 'A' );
else if ( *text >= 'a' && *text <= 'f' )
c = 10 + ( *text - 'a' );
else break;
if ( c >= flex.base ) break;
flex.one *= flex.base;
flex.fpn *= flex.base;
flex.fpn += c;
}
}
if (*text == 'e' || *text == 'E')
{
if (*(++text) == '-')
{
for (++text; *text; ++text)
{
if ( *text >= '0' && *text <= '9' )
c = *text - '0';
else if ( *text >= 'A' && *text <= 'F' )
c = 10 + ( *text - 'A' );
else if ( *text >= 'a' && *text <= 'f' )
c = 10 + ( *text - 'f' );
else break;
if ( c >= flex.base ) break;
flex.exp *= flex.base;
flex.exp -= c;
}
}
else
{
for (++text; *text; ++text)
{
if ( *text >= '0' && *text <= '9' )
c = *text - '0';
else if ( *text >= 'A' && *text <= 'F' )
c = 10 + ( *text - 'A' );
else if ( *text >= 'a' && *text <= 'f' )
c = 10 + ( *text - 'f' );
else break;
if ( c >= flex.base ) break;
flex.exp *= flex.base;
flex.exp += c;
}
}
}
return fpn_make(flex);
}