Well I made some more changes and got as far as this:
Code:gcc -Wall -o "test_fpn" "test_fpn.c" && "./test_fpn"
test.exp 00 mine.exp 00 test.man 000000 mine.man 000000 test.fpn 0.000000e+00 mine.fpn 0.000000e+00 text '0'
test.exp 7F mine.exp 7F test.man 000000 mine.man 000000 test.fpn 1.000000e+00 mine.fpn 1.000000e+00 text '1'
test.exp 85 mine.exp 85 test.man 4A0000 mine.man 4A0000 test.fpn 1.010000e+02 mine.fpn 1.010000e+02 text '101'
test.exp 7B mine.exp 7B test.man 4CCCCD mine.man 4CCCCD test.fpn 1.000000e-01 mine.fpn 1.000000e-01 text '0.1'
test.exp 78 mine.exp 78 test.man 23D70A mine.man 23D70B test.fpn 1.000000e-02 mine.fpn 1.000000e-02 text '0.01'
test.exp 75 mine.exp 75 test.man 03126F mine.man 03126F test.fpn 1.000000e-03 mine.fpn 1.000000e-03 text '0.001'
test.exp 7B mine.exp 75 test.man 4ED917 mine.man 3645A2 test.fpn 1.010000e-01 mine.fpn 1.390625e-03 text '0.101'
Compilation finished successfully.
So seemingly I need to make 1 more change and I'll have the right algorithm for base 10, checking it works for base 2 & 16 will come after I make that change and ensure all my other values appear correctly, the problem right now is I don't know what change to make.Code:LDBL makeFPN( ullong num, ullong fpn, long exp, ulong dig ) {
LDBL dst = {0};
ulong DIG;
long base = 10, pos = 0,
pos_max = FPNT_MAN_BIT,
exp_max = FPNT_EXP_MAX;
ullong one, dec = 0, NUM;
if ( !dig ) return dst;
if ( num == 1 ) {
dst.exp = exp_max - 1;
num = 0;
}
if ( !fpn && !num ) return dst;
dst.man = num;
dst.exp = exp_max;
for ( NUM = num; NUM > 1; ++pos, NUM >>= 1 );
for ( NUM = num, --dig; NUM >= base; --dig, NUM /= base );
for ( one = 1, DIG = dig; DIG; one *= base, --DIG );
#if 0
if ( !num ) for ( DIG = dig, pos = -1; DIG; --pos, --DIG );
#else
if ( !num ) for ( NUM = one, pos = -1; NUM > 1; --pos, NUM >>= 1 );
#endif
dst.exp += pos - 1;
if ( fpn ) dec = 1;
else fpn = 1;
for ( ; pos < pos_max; ++pos ) {
fpn *= 2;
dst.man <<= 1;
if ( fpn >= one ) {
dst.man |= dec;
fpn -= one;
}
}
if ( dst.man ) {
if ( dst.exp < (exp_max-1) )
dst.man++;
pos = 0;
for ( ; pos < exp; ++pos, dst.man *= 2 );
for ( ; pos > exp; --pos, dst.man *= 2 );
}
return dst;
}
typedef struct test_val {
ullong num;
ullong fpn;
long exp;
ulong dig;
} test_val_t;
test_val_t values[] = {
{0}, {1,0,0,1}, {101,0,0,3},
{0,1,0,2}, {0,1,0,3}, {0,1,0,4}, {0,101,0,4}, {101,101,0,6},
{1,0,10,2}, {101,0,10,4}, {0,1,10,2}, {0,101,10,4},
{1,1,10,2}, {3,14,0}, {3,14,10} };
float floats[] = {
0, 1, 101,
0.1, 0.01, 0.001, 0.101, 101.101,
1.0e+10, 101.0e+10, 0.1e+10, 0.101e+10,
1.1e+10, 3.14, 3.14e+10 };
char *text[] = {
"0", "1", "101", "0.1", "0.01", "0.001", "0.101", "101.101",
"1.0e+10", "101.0e+10", "0.1e+10", "0.101e+10", "1.1e+10",
"3.14", "3.14e+10"
};
int main() {
int i;
LDBL test = {0}, mine = {0};
test_val_t *val;
for ( i = 0; i < 7; ++i ) {
test.fpn = floats[i];
val = &(values[i]);
mine = makeFPN( val->num, val->fpn, val->exp, val->dig );
//printf( "test.sig %u mine.sig %u ", test.sig, mine.sig );
printf( "test.exp %02X mine.exp %02X ", test.exp, mine.exp );
printf( "test.man %06X mine.man %06X ", test.man, mine.man );
#if 0
print( "test.hex", test );
putchar(' ');
print( "mine.hex", mine );
putchar(' ');
#endif
printf("test.fpn %e mine.fpn %e text '%s'\n", test.fpn, mine.fpn, text[i] );
}
return 0;
}