#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_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;
int fpn_read (char *text);
char *fpn_text[] = {
"0",
"1", "10", "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",
NULL
};
int main ()
{
size_t i = 0;
while (fpn_text[i] && i < 52)
fpn_read (fpn_text[i++]);
return 0;
}
void printb( 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;
while ( size-- ) {
for ( val = a[size], bit = 1; bit; val <<= 1, bit <<= 1, ++b )
putchar( '0' + !!(val & SCHAR_MIN) );
if ( b >= bits ) return;
}
}
FPN_UNION fpn_make (ulong base, ullong num, ullong fpn, long exp, long dig)
{
FPN_UNION mine = { 0 };
long _exp = exp, exp_bias = FPN_MAX_EXP, exp_bits = FPN_EXP_BIT,
exp_10_max = FPN_MAX_10_EXP,
//_dig = dig,
dig_prior = 0, dig_after = 0,
pos = 0, pos_max = FPN_MAN_BIT;
ullong one = 1, _num = num, NUM, _fpn = fpn;//, man_max = 0x7FFFFF;
if (dig < 1) return mine;
if ( exp <= -exp_10_max )
return mine;
if ( exp >= exp_10_max ) {
mine.exp = ~0;
return mine;
}
if ( num ) for ( NUM = num; NUM; NUM /= base, ++dig_prior );
else if ( fpn ) dig_prior = 1;
else return mine;
dig -= dig_prior;
/* Calculate one */
for (; one <= fpn; one *= base, --dig, ++dig_after);
for (; dig > 0; one *= base, --dig, ++dig_after);
if ( exp > 0 ) {
/* Correct values */
while ( exp > 0 ) {
num *= base;
fpn *= base;
if ( fpn >= one ) {
NUM = fpn / one;
fpn -= NUM * one;
num += NUM;
}
--exp;
}
/* Modify code here */
if ( _num && _fpn && _exp >= exp_bits ) fpn += one / 2;
while ( num && (num & 1u) == 0 ) { num >>= 1; mine.exp++; fpn >>= 1; }
for ( NUM = num; NUM > 1; ++pos, NUM >>= 1 );
}
else if ( exp < 0 ) {
while ( exp < 0 ) {
NUM = num % base;
fpn += NUM * one;
one *= base;
num /= base;
++exp;
}
for ( NUM = fpn; NUM < one; --pos, NUM <<= 1 );
}
else {
/* Calculate normal exponent */
if ( num ) for ( NUM = num; NUM > 1; ++pos, NUM >>= 1 );
else for ( NUM = fpn; NUM < one; --pos, NUM <<= 1 );
}
/* Calculate exponent and mantissa */
mine.man = num;
mine.exp += exp_bias + pos - 1;
for (; pos < pos_max; ++pos)
{
fpn *= 2;
mine.man <<= 1;
if (fpn >= one)
{
mine.man |= 1;
fpn -= one;
}
}
fpn *= 2;
if ( fpn >= one ) mine.man++;
return mine;
}
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 }, mine = { 0 };
_Bool same = 0;
sscanf (text, FPN_SCNf, &(test.fpn));
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');
}
}
}
mine = fpn_make (base, num, fpn, exp, dig);
same = ( test.man == mine.man &&
test.exp == mine.exp && test.sig == mine.sig );
printf("same = %u ", same );
#define FILTER_CORRECT_FPN 1
if ( !same ) {
putchar('\n');
num = test.man;
printb( &num, FPN_MAN_BIT );
putchar('\n');
num = mine.man;
printb( &num, FPN_MAN_BIT );
putchar('\n');
#if !FILTER_CORRECT_FPN
}
#endif
printf ("test.man = %013llX ", (ullong)(test.man) );
printf ("mine.man = %013llX ", (ullong)(mine.man));
printf ("exp t = %03X m = %03X ", test.exp, mine.exp);
printf ("sig t = %u m = %u ", test.sig, mine.sig);
printf ("fpn t = " FPN_SCNe " m = " FPN_SCNe " ", test.fpn, mine.fpn);
#if FILTER_CORRECT_FPN
}
#endif
printf ("value '%s'\n", _text);
return 0;
}