Code:
#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 HALF_MAN_BIT 10
#define HALF_EXP_BIT 5
#define LDBL_MAN_BIT 52
#define LDBL_EXP_BIT 37
#define FLT_SCNf "%f"
#define FLT_SCNe "%e"
#define FLT_MAN_BIT 23
#define FLT_EXP_BIT 8
typedef union FLT_UNION
{
float fpn;
uchar raw[sizeof(float)];
struct
{
ullong man:FLT_MAN_BIT;
ullong exp:FLT_EXP_BIT;
ullong sig:1;
};
} FLT_UNION;
#define DBL_SCNf "%lf"
#define DBL_SCNe "%le"
#define DBL_MAN_BIT 52
#define DBL_EXP_BIT 11
typedef union DBL_UNION
{
double fpn;
uchar raw[sizeof(double)];
struct
{
ullong man:DBL_MAN_BIT;
ullong exp:DBL_EXP_BIT;
ullong sig:1;
};
} DBL_UNION;
#define FPN_PFX(VAL) FLT##_##VAL
#define FPN_MAX FPN_PFX(_MAX)
#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_MAX_10_EXP FPN_PFX(MAX_10_EXP)
typedef FPN_PFX(UNION) FPN_UNION;
typedef struct FPN_RET {
long pos;
FPN_UNION val;
} FPN_RET;
int fpn_read (char *text);
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",
NULL
};
int main ()
{
size_t i = 0, wrong = 0;
while (fpn_text[i] && i < 110)
wrong += fpn_read (fpn_text[i++]);
while (fpn_text[i]) ++i;
printf( "Count = %zu, Wrong = %zu", i, wrong );
return 0;
}
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(text);
while ( size-- ) {
for ( val = a[size], bit = 1; bit; val <<= 1, bit <<= 1, ++b ) {
//if ( b == bits ) return;
putchar( '0' + !!(val & SCHAR_MIN) );
}
if ( b >= bits ) return;
}
}
FPN_RET fpn_make ( ulong base, ullong num, ullong fpn, long exp, long dig)
{
FPN_RET ret = {0};
long //_exp = exp,
exp_bias = FPN_MAX_EXP,
exp_10_max = FPN_MAX_10_EXP,
pos = 0, pos_max = FPN_MAN_BIT;
ullong one = 1, NUM;
if (dig < 1) return ret;
if ( exp <= -exp_10_max )
return ret;
if ( exp >= exp_10_max ) {
ret.val.exp = ~0;
return ret;
}
if ( num ) for ( NUM = num; NUM; NUM /= base, --dig );
else if ( fpn ) --dig;
else return ret;
/* Calculate one */
for (; one <= fpn; one *= base, --dig );
for (; dig > 0; one *= base, --dig );
/* Preserve exponent in case we need it later */
pos = exp;
while ( pos > 0 ) {
num *= base;
fpn *= base;
if ( fpn >= one ) {
NUM = fpn / one;
fpn -= NUM * one;
num += NUM;
}
--pos;
}
while ( pos < 0 ) {
NUM = num % base;
fpn += NUM * one;
one *= base;
num /= base;
++pos;
}
/* Calculate normal exponent */
pos = 0;
if ( num ) {
for ( ; !(num & 1); ret.val.exp++, num >>= 1 );
for ( NUM = num; NUM > 1; ++pos, NUM >>= 1 );
}
else for ( NUM = fpn; NUM < one; --pos, NUM <<= 1 );
/* Set exponent and mantissa */
ret.val.man = num;
ret.val.exp += exp_bias + pos - 1;
ret.pos = pos;
for ( ; pos < pos_max; ++pos)
{
fpn *= 2;
ret.val.man <<= 1;
if (fpn >= one)
{
ret.val.man |= 1;
fpn -= one;
}
}
fpn *= 2;
if ( fpn >= one ) ret.val.man++;
return ret;
}
int fpn_read (char *text)
{
char *_text = text;
ulong base = 10;
long exp = 0, dig = 0;
ullong num = 0, fpn = 0;
FPN_UNION test = { 0 };
FPN_RET ret = {0};
_Bool same = 0, neg = (*text == '-');
sscanf (text, FPN_SCNf, &(test.fpn));
if ( neg || *text == '+' ) {
++text;
}
while (*text == '0')
++text;
for (; *text >= '0' && *text <= '9'; ++text)
{
num *= base;
num += (*text - '0');
++dig;
}
if (dig < 1)
dig = 1;
if (*text == '.')
{
for (++text; *text >= '0' && *text <= '9'; ++text)
{
fpn *= base;
fpn += (*text - '0');
++dig;
}
}
if (*text == 'e' || *text == 'E')
{
if (*(++text) == '-')
{
for (++text; *text >= '0' && *text <= '9'; ++text)
{
exp *= base;
exp -= (*text - '0');
}
}
else
{
for (++text; *text >= '0' && *text <= '9'; ++text)
{
exp *= base;
exp += (*text - '0');
}
}
}
ret = fpn_make (base, num, fpn, exp, dig);
ret.val.sig = neg;
same = ( test.man == ret.val.man &&
test.exp == ret.val.exp && test.sig == ret.val.sig );
if ( !same ) {
printf("pos = %ld\n", ret.pos );
#if 0
printb( "num = ", &num, FPN_MAN_BIT );
putchar('\n');
printb( "fpn = ", &fpn, FPN_MAN_BIT );
putchar('\n');
#endif
num = test.man;
printb( "gcc = ", &num, FPN_MAN_BIT );
putchar('\n');
num = ret.val.man;
printb( "mcc = ", &num, FPN_MAN_BIT );
putchar('\n');
printf ("test.man = %013llX ", (ullong)(test.man) );
printf ("mine.man = %013llX ", (ullong)(ret.val.man));
printf ("exp t = %03X m = %03X\n", test.exp, ret.val.exp);
printf ("fpn t = " FPN_SCNe " m = " FPN_SCNe " ", test.fpn, ret.val.fpn);
printf ("value '%s'\n", _text);
}
return !same;
}