#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 uflt
{
float fpn;
uchar raw[sizeof(float)];
struct
{
ullong man:FLT_MAN_BIT;
ullong exp:FLT_EXP_BIT;
ullong sig:1;
};
} uflt;
#define DBL_SCNf "%lf"
#define DBL_SCNe "%le"
#define DBL_MAN_BIT 52
#define DBL_EXP_BIT 11
typedef union udbl
{
double fpn;
uchar raw[sizeof(double)];
struct
{
ullong man:DBL_MAN_BIT;
ullong exp:DBL_EXP_BIT;
ullong sig:1;
};
} udbl;
typedef uflt ufpn;
#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)
ufpn
fpn_make (ulong base, ullong num, ullong fpn, long exp, long dig)
{
ufpn mine = { 0 };
long exp_copy = exp, exp_bias = FPN_MAX_EXP, exp_bits = FPN_EXP_BIT,
exp_10_max = FPN_MAX_10_EXP,
pos = 0, pos_max = FPN_MAN_BIT;
ullong one = 1, NUM;//, man_max = 0x7FFFFF;
if (dig < 1) return mine;
/* Calculate one */
if ( num ) for ( NUM = num; NUM; --dig, NUM /= base );
else if ( fpn ) --dig;
else return mine;
for (; one <= fpn; one *= base, --dig);
for (; dig > 0; one *= base, --dig);
/* Calculate abnormal exponent */
if ( exp ) {
while ( exp > 0 ) {
num *= base;
fpn *= base;
if ( fpn >= one ) {
NUM = (fpn / one);
fpn -= (NUM * one);
num += NUM;
}
--exp;
}
while ( exp < 0 ) {
NUM = num % base;
fpn += NUM * one;
one *= base;
num /= base;
++exp;
}
exp = exp_copy;
/* My modified "hack" */
if ( exp >= exp_bits ) {
mine.exp += exp;
NUM = (num >> exp);
}
else NUM = num;
num = NUM;
}
else NUM = num;
if ( exp > exp_10_max )
mine.exp = ~0;
else if ( exp < -exp_10_max )
mine.exp = 0;
else {
mine.man = NUM;
/* Calculate normal exponent */
if ( num ) for ( ; num > 1; ++pos, num >>= 1 );
else for ( NUM = fpn; NUM < one; --pos, NUM <<= 1 );
/* Calculate exponent and mantissa */
mine.exp += exp_bias + pos - 1;
//printf("pos = %ld ", pos );
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 *fpn_text[] = {
"0",
"1", "10", "100", "101",
"1.1", "1.01", "1.001", "1.101",
"0.1", "0.01", "0.001", "0.101",
"1e+1", "1e+8", "1e+10", "1e+100",
"1e-1", "1e-8", "1e-10", "1e-100",
".1e+1", ".1e+8", ".1e+10", ".1e+100",
".1e-1", ".1e-8", ".1e-10", ".1e-100",
NULL
};
int main ()
{
size_t i = 0;
while (fpn_text[i] && i < 25)
fpn_read (fpn_text[i++]);
return 0;
}
int fpn_read (char *text)
{
char *_text = text;
ulong base = 10;
long exp = 0, dig = 0;
ullong num = 0, fpn = 0;
ufpn test = { 0 }, mine = { 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);
#define FILTER_CORRECT_FPN 0
#if FILTER_CORRECT_FPN
if ( test.man == mine.man &&
test.exp == mine.exp && test.sig == mine.sig )
printf("mine is the same as test for ");
else {
#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;
}