Thread: FPN math

1. 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.```
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;
}```
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.

2. GOT IT!
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 7B test.man 4ED917 mine.man 4ED917 test.fpn 1.010000e-01 mine.fpn 1.010000e-01 text '0.101'
Compilation finished successfully.```
Code:
```	if ( !num ) {
NUM = one;
pos = -1;
for ( ; NUM > fpn; --pos, NUM >>= 1 );
for ( ; NUM >= base; ++pos, NUM /= base );
}```
I'll fix the off by 1 value later, but this is definitly close enough for now

Edit:
Just to satisfy my curiosty I tried the full 15, then I remembered the e+10 part, so it seems a flat float is mostly fine but the exponent still needs further correction
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 7B test.man 4ED917 mine.man 4ED917 test.fpn 1.010000e-01 mine.fpn 1.010000e-01 text '0.101'
test.exp 85 mine.exp 85 test.man 4A33B6 mine.man 4A33B6 test.fpn 1.011010e+02 mine.fpn 1.011010e+02 text '101.101'
test.exp A0 mine.exp 7F test.man 1502F9 mine.man 000000 test.fpn 1.000000e+10 mine.fpn 1.000000e+00 text '1.0e+10'
Compilation finished successfully.```

3. Potentially on right track with this one, at least the exponent is closer than I've ever had it before:
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.000000 mine.fpn 0.000000 text '0'
test.exp 7F mine.exp 7F test.man 000000 mine.man 000000 test.fpn 1.000000 mine.fpn 1.000000 text '1'
test.exp 85 mine.exp 85 test.man 4A0000 mine.man 4A0000 test.fpn 101.000000 mine.fpn 101.000000 text '101'
test.exp 7B mine.exp 7B test.man 4CCCCD mine.man 4CCCCD test.fpn 0.100000 mine.fpn 0.100000 text '0.1'
test.exp 78 mine.exp 78 test.man 23D70A mine.man 23D70B test.fpn 0.010000 mine.fpn 0.010000 text '0.01'
test.exp 75 mine.exp 75 test.man 03126F mine.man 03126F test.fpn 0.001000 mine.fpn 0.001000 text '0.001'
test.exp 7B mine.exp 7B test.man 4ED917 mine.man 4ED917 test.fpn 0.101000 mine.fpn 0.101000 text '0.101'
test.exp 85 mine.exp 85 test.man 4A33B6 mine.man 4A33B6 test.fpn 101.100998 mine.fpn 101.100998 text '101.101'
test.exp A0 mine.exp 9F test.man 1502F9 mine.man 0147AE test.fpn 10000000000.000000 mine.fpn 4337916928.000000 text '1.0e+10'
Compilation finished successfully.```
Code:
```...
for ( one = 1, DIG = dig; DIG; one *= base, --DIG );
if ( fpn ) {
dec = 1;
if ( pos == -1 ) {
NUM = one;
for ( ; NUM > fpn; --pos, NUM >>= 1 );
for ( ; NUM >= base; ++pos, NUM /= base );
}
}
else fpn = 1;
if ( exp > 0 ) {
dec = 1;
while ( exp < exp_max ) {
exp <<= 4;
one *= base;
}
}
else exp = exp_max;
dst.exp = exp + (pos - 1);
for ( ; pos < pos_max; ++pos ) {
...```
Edit: Got the exponent to match by just incrementing it after shifting it. Still no idea how to modify pos so that things match up on the mantissa

4. For more verbose results:
Code:
```void printb( uchar *hex, size_t size ) {
size_t i;
uchar bit;
for ( i = 0; i < size; ++i ) {
putchar(' ');
for ( bit = SCHAR_MIN; bit; bit >>= 1 ) {
putchar( '0' + !!(hex[i] & bit) );
}
}
}

void print( char *text, LDBL val ) {
printf("%s",text);
#if 1
printb( val.hex, sizeof(FPNT) );
#else
for ( size_t i = 0; i < sizeof(FPNT); ++i ) {
printf( " %02X", val.hex[i] );
}
#endif
}
...
for ( i = 0; i < 9; ++i ) {
test.fpn = floats[i];
val = &(values[i]);
mine = makeFPN( val->num, val->fpn, val->exp, val->dig );
printf( "test.exp %02X mine.exp %02X ", test.exp, mine.exp );
printf( "test.man %06X mine.man %06X ", test.man, mine.man );
printf("test.fpn %f mine.fpn %f text '%s'\n", test.fpn, mine.fpn, text[i] );
if ( test.man != mine.man ) {
print( "test.hex", test );
putchar('\n');
print( "mine.hex", mine );
putchar('\n');
}
}```
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.000000 mine.fpn 0.000000 text '0'
test.exp 7F mine.exp 7F test.man 000000 mine.man 000000 test.fpn 1.000000 mine.fpn 1.000000 text '1'
test.exp 85 mine.exp 85 test.man 4A0000 mine.man 4A0000 test.fpn 101.000000 mine.fpn 101.000000 text '101'
test.exp 7B mine.exp 7B test.man 4CCCCD mine.man 4CCCCD test.fpn 0.100000 mine.fpn 0.100000 text '0.1'
test.exp 78 mine.exp 78 test.man 23D70A mine.man 23D70B test.fpn 0.010000 mine.fpn 0.010000 text '0.01'
test.hex 00001010 11010111 00100011 00111100
mine.hex 00001011 11010111 00100011 00111100
test.exp 75 mine.exp 75 test.man 03126F mine.man 03126F test.fpn 0.001000 mine.fpn 0.001000 text '0.001'
test.exp 7B mine.exp 7B test.man 4ED917 mine.man 4ED917 test.fpn 0.101000 mine.fpn 0.101000 text '0.101'
test.exp 85 mine.exp 85 test.man 4A33B6 mine.man 4A33B6 test.fpn 101.100998 mine.fpn 101.100998 text '101.101'
test.exp A0 mine.exp A0 test.man 1502F9 mine.man 0147AE test.fpn 10000000000.000000 mine.fpn 8675833856.000000 text '1.0e+10'
test.hex 11111001 00000010 00010101 01010000
mine.hex 10101110 01000111 00000001 01010000
Compilation finished successfully.```

5. Realised everything was displayed backwards so I just changed the above to this:
Code:
```void printb( uchar *hex, size_t bits ) {
size_t B = (bits / CHAR_BIT)// + !!(bits % CHAR_BIT)
, b = 0;
uchar bit;
while ( b < bits ) {
putchar(' ');
bit = SCHAR_MIN;
if ( !b ) bit >>= (CHAR_BIT - (bits % CHAR_BIT));
for ( ; bit && b < bits; bit >>= 1, ++b ) {
putchar( '0' + !!(hex[B] & bit) );
}
--B;
}
}

void print( char *text, LDBL val ) {
printf("%s",text);
#if 1
ullong man = val.man;
printb( (uchar*)(&man), FPNT_MAN_BIT );
#else
for ( size_t i = 0; i < sizeof(FPNT); ++i ) {
printf( " %02X", val.hex[i] );
}
#endif
}```
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.000000 mine.fpn 0.000000 text '0'
test.exp 7F mine.exp 7F test.man 000000 mine.man 000000 test.fpn 1.000000 mine.fpn 1.000000 text '1'
test.exp 85 mine.exp 85 test.man 4A0000 mine.man 4A0000 test.fpn 101.000000 mine.fpn 101.000000 text '101'
test.exp 7B mine.exp 7B test.man 4CCCCD mine.man 4CCCCD test.fpn 0.100000 mine.fpn 0.100000 text '0.1'
test.exp 78 mine.exp 78 test.man 23D70A mine.man 23D70B test.fpn 0.010000 mine.fpn 0.010000 text '0.01'
test.hex 0100011 11010111 00001010
mine.hex 0100011 11010111 00001011
test.exp 75 mine.exp 75 test.man 03126F mine.man 03126F test.fpn 0.001000 mine.fpn 0.001000 text '0.001'
test.exp 7B mine.exp 7B test.man 4ED917 mine.man 4ED917 test.fpn 0.101000 mine.fpn 0.101000 text '0.101'
test.exp 85 mine.exp 85 test.man 4A33B6 mine.man 4A33B6 test.fpn 101.100998 mine.fpn 101.100998 text '101.101'
test.exp A0 mine.exp A0 test.man 1502F9 mine.man 0147AE test.fpn 10000000000.000000 mine.fpn 8675833856.000000 text '1.0e+10'
test.hex 0010101 00000010 11111001
mine.hex 0000001 01000111 10101110
Compilation finished successfully.```

6. Well I finally got my computer back up and running (its the reason I went quiet for a few days) and was gonna put my code on online gdb but then decided nah start afresh instead (GDB online Debugger | Code, Compile, Run, Debug online C, C++), wound up resolving that off by one error and got as far as trying to use the exponent parameter before hitting a road block:
Code:
```man t = 4ED917 m = 4ED917 exp t = 7B m = 7B sig t = 0 m = 0
fpn t = 1.010000e-01 m = 1.010000e-01, text = '0.101'
exp = 1 man t = 200000 m = 200000 exp t = 82 m = 82 sig t = 0 m = 0
fpn t = 1.000000e+01 m = 1.000000e+01, text = '1e+1'
exp = 10 man t = 1502F9 m = 000008 exp t = A0 m = 94 sig t = 0 m = 0
fpn t = 1.000000e+10 m = 2.097154e+06, text = '1e+10'

...Program finished with exit code 0```
You'll have to visit the link for a full output, the code on the other hand I can give in full
Code:
```#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;

typedef union sfpn
{
float fpn;
uchar raw;
struct
{
ullong man:23;
ullong exp:8;
ullong sig:1;
};
} sfpn;

sfpn
fpn_make (ulong base, ullong num, ullong fpn, long exp, long dig)
{
sfpn mine = { 0 };
long exp_max = FLT_MAX_EXP, pos = 0, pos_max = 23;
ullong one = 1, NUM;
if (dig < 1)
return mine;
if (num)
{
for (NUM = num; NUM; NUM /= base, --dig);
for (NUM = num; NUM > 1 && pos < pos_max; NUM >>= 1, ++pos);
for (; one <= fpn; one *= base, --dig);
for (; dig > 0; one *= base, --dig);
}
else if (fpn)
{
for ( --dig; one <= fpn; one *= base, --dig );
for ( pos = -4; dig > 0; one *= base, --dig, pos -= 3 );
}
else return mine;
if ( exp ) {
printf("exp = %ld ", exp );
if ( exp > 0 )
pos += (exp * 2);
else
pos += (exp * 4);
mine.exp = exp_max + pos;
}
else
mine.exp = exp_max + (pos - 1);
mine.man = num;
for (NUM = fpn; pos < pos_max; ++pos)
{
NUM *= 2;
mine.man <<= 1;
if (NUM >= one)
{
mine.man |= 1;
NUM -= one;
}
}
NUM *= 2;
if ( NUM >= one ) mine.man |= 1;
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+10", "1e+100",
"1e-1", "1e-10", "1e-100",
NULL
};

int main ()
{
size_t i = 0;
while (fpn_text[i] && i < 15)
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;
sfpn test = { 0 }, mine = { 0 };
sscanf (text, "%f", &(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);
printf ("man t = %06X m = %06X ", test.man, mine.man);
printf ("exp t = %02X m = %02X ", test.exp, mine.exp);
printf ("sig t = %u m = %u\n", test.sig, mine.sig);
printf ("fpn t = %e m = %e, ", test.fpn, mine.fpn);
printf ("text = '%s'\n", _text);
return 0;
}```

7. Well I managed to touch upon what I'm supposed to do with the exponent, turns out that gets processed 1st:
Code:
```...
man t = 3EBC20 m = 75E100 exp t = 99 m = 96 sig t = 0 m = 0
fpn t = 1.000000e+08 m = 1.611392e+07, text = '1e+8'
...```
Code:
```...
if (num)
{
for (NUM = num; NUM; NUM /= base, --dig);
if ( exp > 0 ) {
while ( exp-- ) {
num *= base;
}
}
for (NUM = num; NUM > 1 && pos < pos_max; NUM >>= 1, ++pos);
for (; one <= fpn; one *= base, --dig);
for (; dig > 0; one *= base, --dig);
}
...```
That was fine from 1 to 7 but as soon as I tried +8 I got the above result, I must be missing something, the question is what?

8. I've just read the chapter on floating point numbers in Knuth's TAOCP (Vol. 2) and also some of the IEEE specification and all I have to say is that I'm glad you're doing this and not me LOL

9. Originally Posted by Hodor
I've just read the chapter on floating point numbers in Knuth's TAOCP (Vol. 2) and also some of the IEEE specification and all I have to say is that I'm glad you're doing this and not me LOL
Unhelpful but fair enough, at least I have a rough idea of how to shift the fpn into the int part but I'll deal with that when I can get consistant results with 1e+#, one step at a time after all

10. While playing around with my function I stumbled across what I should fill mine.exp with when handling the e+# part of a value:
Code:
```gcc -Wall -o "test_fpn" "test_fpn.c" && "./test_fpn"
man t = 000000 m = 000000 exp t = 00 m = 00 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, text = '0'
man t = 000000 m = 000000 exp t = 7F m = 7F sig t = 0 m = 0 fpn t = 1.000000e+00 m = 1.000000e+00, text = '1'
man t = 200000 m = 200000 exp t = 82 m = 82 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, text = '10'
man t = 480000 m = 480000 exp t = 85 m = 85 sig t = 0 m = 0 fpn t = 1.000000e+02 m = 1.000000e+02, text = '100'
man t = 4A0000 m = 4A0000 exp t = 85 m = 85 sig t = 0 m = 0 fpn t = 1.010000e+02 m = 1.010000e+02, text = '101'
man t = 0CCCCD m = 0CCCCD exp t = 7F m = 7F sig t = 0 m = 0 fpn t = 1.100000e+00 m = 1.100000e+00, text = '1.1'
man t = 0147AE m = 0147AE exp t = 7F m = 7F sig t = 0 m = 0 fpn t = 1.010000e+00 m = 1.010000e+00, text = '1.01'
man t = 0020C5 m = 0020C5 exp t = 7F m = 7F sig t = 0 m = 0 fpn t = 1.001000e+00 m = 1.001000e+00, text = '1.001'
man t = 0CED91 m = 0CED91 exp t = 7F m = 7F sig t = 0 m = 0 fpn t = 1.101000e+00 m = 1.101000e+00, text = '1.101'
man t = 4CCCCD m = 4CCCCD exp t = 7B m = 7B sig t = 0 m = 0 fpn t = 1.000000e-01 m = 1.000000e-01, text = '0.1'
man t = 23D70A m = 23D70A exp t = 78 m = 78 sig t = 0 m = 0 fpn t = 1.000000e-02 m = 1.000000e-02, text = '0.01'
man t = 03126F m = 03126F exp t = 75 m = 75 sig t = 0 m = 0 fpn t = 1.000000e-03 m = 1.000000e-03, text = '0.001'
man t = 4ED917 m = 4ED917 exp t = 7B m = 7B sig t = 0 m = 0 fpn t = 1.010000e-01 m = 1.010000e-01, text = '0.101'
man t = 200000 m = 200000 exp t = 82 m = 82 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, text = '1e+1'
man t = 3EBC20 m = 75E100 exp t = 99 m = 99 sig t = 0 m = 0 fpn t = 1.000000e+08 m = 1.289114e+08, text = '1e+8'
Compilation finished successfully.```
Code:
```sfpn
fpn_make (ulong base, ullong num, ullong fpn, long exp, long dig)
{
sfpn mine = { 0 };
long exp_bias = FLT_MAX_EXP, pos = 0, pos_max = 23;
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 ) {
/* Normalise the integer part */
for ( NUM = num; NUM >= base;
fpn += (NUM % base) * one, one *= base, NUM /= base );
if ( exp > 0 ) {
while ( exp-- ) num *= base;
}
}
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;
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 |= 1;
return mine;
}```

11. Well I finally got the exponent AND mantissa right in 1e+# scenario, although by means of a hack (or at least I'm calling it that until I do more testing 2mw)
Code:
```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,
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 ) {
#if 0
/* "Normalise" the integer part */
while ( num >= base ) {
fpn += (num % base) * one;
one *= base;
num /= base;
}
#endif
/* Move exp left */
if ( exp > 0 ) {
/* This overshoots by 3 bits on 1e+8 */
while ( exp > 0 ) {
num *= base;
fpn *= base;
if ( fpn >= one ) {
NUM = (fpn / one);
fpn -= (NUM * one);
num += NUM;
}
--exp;
}
}
exp = exp_copy;
/* This is my "hack" */
NUM = num;
while ( exp >= exp_bits ) {
NUM >>= exp_bits;
exp -= exp_bits;
mine.exp += exp_bits;
}
/* Not yet confirmed I need to keep num the same, this is easy for me to comment out */
num = NUM;
}
else NUM = num;
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;
}```

12. Erm, decided to test tonight after all, turned my hack was close to what should be done, I was just slightly off with what I was doing, currently I have 1e+/-# seemingly fully working, .1e+# (and probably .1e-#) give just ever so slightly the wrong mantissa:
Code:
```gcc -Wall -o "test_fpn" "test_fpn.c" && "./test_fpn"
test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '0'
test.man = 0000000000000 mine.man = 0000000000000 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.000000e+00 m = 1.000000e+00, value '1'
test.man = 0000000200000 mine.man = 0000000200000 exp t = 082 m = 082 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, value '10'
test.man = 0000000480000 mine.man = 0000000480000 exp t = 085 m = 085 sig t = 0 m = 0 fpn t = 1.000000e+02 m = 1.000000e+02, value '100'
test.man = 00000004A0000 mine.man = 00000004A0000 exp t = 085 m = 085 sig t = 0 m = 0 fpn t = 1.010000e+02 m = 1.010000e+02, value '101'
test.man = 00000000CCCCD mine.man = 00000000CCCCD exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.100000e+00 m = 1.100000e+00, value '1.1'
test.man = 00000000147AE mine.man = 00000000147AE exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.010000e+00 m = 1.010000e+00, value '1.01'
test.man = 00000000020C5 mine.man = 00000000020C5 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.001000e+00 m = 1.001000e+00, value '1.001'
test.man = 00000000CED91 mine.man = 00000000CED91 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.101000e+00 m = 1.101000e+00, value '1.101'
test.man = 00000004CCCCD mine.man = 00000004CCCCD exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.000000e-01 m = 1.000000e-01, value '0.1'
test.man = 000000023D70A mine.man = 000000023D70A exp t = 078 m = 078 sig t = 0 m = 0 fpn t = 1.000000e-02 m = 1.000000e-02, value '0.01'
test.man = 000000003126F mine.man = 000000003126F exp t = 075 m = 075 sig t = 0 m = 0 fpn t = 1.000000e-03 m = 1.000000e-03, value '0.001'
test.man = 00000004ED917 mine.man = 00000004ED917 exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.010000e-01 m = 1.010000e-01, value '0.101'
test.man = 0000000200000 mine.man = 0000000200000 exp t = 082 m = 082 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, value '1e+1'
test.man = 00000003EBC20 mine.man = 00000003EBC20 exp t = 099 m = 099 sig t = 0 m = 0 fpn t = 1.000000e+08 m = 1.000000e+08, value '1e+8'
test.man = 00000001502F9 mine.man = 00000001502F9 exp t = 0A0 m = 0A0 sig t = 0 m = 0 fpn t = 1.000000e+10 m = 1.000000e+10, value '1e+10'
test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '1e+100'
test.man = 00000004CCCCD mine.man = 00000004CCCCD exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.000000e-01 m = 1.000000e-01, value '1e-1'
test.man = 00000002BCC77 mine.man = 00000002BCC77 exp t = 064 m = 064 sig t = 0 m = 0 fpn t = 1.000000e-08 m = 1.000000e-08, value '1e-8'
test.man = 00000005BE6FF mine.man = 00000005BE6FF exp t = 05D m = 05D sig t = 0 m = 0 fpn t = 1.000000e-10 m = 1.000000e-10, value '1e-10'
test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '1e-100'
test.man = 0000000000000 mine.man = 0000000000000 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.000000e+00 m = 1.000000e+00, value '.1e+1'
test.man = 0000000189680 mine.man = 0000000189600 exp t = 096 m = 096 sig t = 0 m = 0 fpn t = 1.000000e+07 m = 9.999872e+06, value '.1e+8'
test.man = 00000006E6B28 mine.man = 00000006E6B20 exp t = 09C m = 09C sig t = 0 m = 0 fpn t = 1.000000e+09 m = 9.999995e+08, value '.1e+10'
test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '.1e+100'
Compilation finished successfully.```
Code:
```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;
}```
Right, this time I will actually go to sleep, this is by far close enough for tonight.

Edit: Didn't realise I needed to re-share my "project" on the online gdb site, here you go, a carbon copy of my file, no edits done to shorten output line length.

GDB online Debugger | Code, Compile, Run, Debug online C, C++

13. GDB online Debugger | Code, Compile, Run, Debug online C, C++
I've almost cracked it, it seems I'm one more piece of code away from correct reading of the value (at least in positive cases)
Code:
```gcc -Wall -o "test_fpn" "test_fpn.c" && "./test_fpn"
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '0'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.000000e+00 m = 1.000000e+00, value '1'
same = 1 test.man = 0000000200000 mine.man = 0000000200000 exp t = 082 m = 082 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, value '10'
same = 1 test.man = 0000000480000 mine.man = 0000000480000 exp t = 085 m = 085 sig t = 0 m = 0 fpn t = 1.000000e+02 m = 1.000000e+02, value '100'
same = 1 test.man = 00000004A0000 mine.man = 00000004A0000 exp t = 085 m = 085 sig t = 0 m = 0 fpn t = 1.010000e+02 m = 1.010000e+02, value '101'
same = 1 test.man = 00000000CCCCD mine.man = 00000000CCCCD exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.100000e+00 m = 1.100000e+00, value '1.1'
same = 1 test.man = 00000000147AE mine.man = 00000000147AE exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.010000e+00 m = 1.010000e+00, value '1.01'
same = 1 test.man = 00000000020C5 mine.man = 00000000020C5 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.001000e+00 m = 1.001000e+00, value '1.001'
same = 1 test.man = 00000000CED91 mine.man = 00000000CED91 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.101000e+00 m = 1.101000e+00, value '1.101'
same = 1 test.man = 000000048F5C3 mine.man = 000000048F5C3 exp t = 080 m = 080 sig t = 0 m = 0 fpn t = 3.140000e+00 m = 3.140000e+00, value '3.14'
same = 1 test.man = 00000004CCCCD mine.man = 00000004CCCCD exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.000000e-01 m = 1.000000e-01, value '0.1'
same = 1 test.man = 000000023D70A mine.man = 000000023D70A exp t = 078 m = 078 sig t = 0 m = 0 fpn t = 1.000000e-02 m = 1.000000e-02, value '0.01'
same = 1 test.man = 000000003126F mine.man = 000000003126F exp t = 075 m = 075 sig t = 0 m = 0 fpn t = 1.000000e-03 m = 1.000000e-03, value '0.001'
same = 1 test.man = 00000004ED917 mine.man = 00000004ED917 exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.010000e-01 m = 1.010000e-01, value '0.101'
same = 1 test.man = 0000000200000 mine.man = 0000000200000 exp t = 082 m = 082 sig t = 0 m = 0 fpn t = 1.000000e+01 m = 1.000000e+01, value '1e+1'
same = 1 test.man = 00000003EBC20 mine.man = 00000003EBC20 exp t = 099 m = 099 sig t = 0 m = 0 fpn t = 1.000000e+08 m = 1.000000e+08, value '1e+8'
same = 1 test.man = 00000001502F9 mine.man = 00000001502F9 exp t = 0A0 m = 0A0 sig t = 0 m = 0 fpn t = 1.000000e+10 m = 1.000000e+10, value '1e+10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '1e+100'
same = 1 test.man = 0000000700000 mine.man = 0000000700000 exp t = 083 m = 083 sig t = 0 m = 0 fpn t = 3.000000e+01 m = 3.000000e+01, value '3e+1'
same = 1 test.man = 00000004CCCCD mine.man = 00000004CCCCD exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.000000e-01 m = 1.000000e-01, value '1e-1'
same = 1 test.man = 00000002BCC77 mine.man = 00000002BCC77 exp t = 064 m = 064 sig t = 0 m = 0 fpn t = 1.000000e-08 m = 1.000000e-08, value '1e-8'
same = 1 test.man = 00000005BE6FF mine.man = 00000005BE6FF exp t = 05D m = 05D sig t = 0 m = 0 fpn t = 1.000000e-10 m = 1.000000e-10, value '1e-10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '1e-100'
same = 1 test.man = 000000019999A mine.man = 000000019999A exp t = 07D m = 07D sig t = 0 m = 0 fpn t = 3.000000e-01 m = 3.000000e-01, value '3e-1'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 07F m = 07F sig t = 0 m = 0 fpn t = 1.000000e+00 m = 1.000000e+00, value '.1e+1'
same = 1 test.man = 0000000189680 mine.man = 0000000189680 exp t = 096 m = 096 sig t = 0 m = 0 fpn t = 1.000000e+07 m = 1.000000e+07, value '.1e+8'
same = 1 test.man = 00000006E6B28 mine.man = 00000006E6B28 exp t = 09C m = 09C sig t = 0 m = 0 fpn t = 1.000000e+09 m = 1.000000e+09, value '.1e+10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '.1e+100'
same = 1 test.man = 0000000400000 mine.man = 0000000400000 exp t = 080 m = 080 sig t = 0 m = 0 fpn t = 3.000000e+00 m = 3.000000e+00, value '.3e+1'
same = 1 test.man = 000000023D70A mine.man = 000000023D70A exp t = 078 m = 078 sig t = 0 m = 0 fpn t = 1.000000e-02 m = 1.000000e-02, value '.1e-1'
same = 1 test.man = 000000009705F mine.man = 000000009705F exp t = 061 m = 061 sig t = 0 m = 0 fpn t = 1.000000e-09 m = 1.000000e-09, value '.1e-8'
same = 1 test.man = 00000002FEBFF mine.man = 00000002FEBFF exp t = 05A m = 05A sig t = 0 m = 0 fpn t = 1.000000e-11 m = 1.000000e-11, value '.1e-10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '.1e-100'
same = 1 test.man = 000000075C28F mine.man = 000000075C28F exp t = 079 m = 079 sig t = 0 m = 0 fpn t = 3.000000e-02 m = 3.000000e-02, value '.3e-1'
same = 1 test.man = 0000000300000 mine.man = 0000000300000 exp t = 082 m = 082 sig t = 0 m = 0 fpn t = 1.100000e+01 m = 1.100000e+01, value '1.1e+1'
same = 1 test.man = 000000051CEF0 mine.man = 000000051CEF0 exp t = 099 m = 099 sig t = 0 m = 0 fpn t = 1.100000e+08 m = 1.100000e+08, value '1.1e+8'
same = 1 test.man = 000000023E9AC mine.man = 000000023E9AC exp t = 0A0 m = 0A0 sig t = 0 m = 0 fpn t = 1.100000e+10 m = 1.100000e+10, value '1.1e+10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '1.1e+100'
same = 1 test.man = 0000000780000 mine.man = 0000000780000 exp t = 083 m = 083 sig t = 0 m = 0 fpn t = 3.100000e+01 m = 3.100000e+01, value '3.1e+1'
same = 1 test.man = 00000006147AE mine.man = 00000006147AE exp t = 07B m = 07B sig t = 0 m = 0 fpn t = 1.100000e-01 m = 1.100000e-01, value '1.1e-1'
same = 1 test.man = 00000003CFA83 mine.man = 00000003CFA83 exp t = 064 m = 064 sig t = 0 m = 0 fpn t = 1.100000e-08 m = 1.100000e-08, value '1.1e-8'
same = 1 test.man = 000000071E47F mine.man = 000000071E47F exp t = 05D m = 05D sig t = 0 m = 0 fpn t = 1.100000e-10 m = 1.100000e-10, value '1.1e-10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '1.1e-100'
same = 1 test.man = 00000001EB852 mine.man = 00000001EB852 exp t = 07D m = 07D sig t = 0 m = 0 fpn t = 3.100000e-01 m = 3.100000e-01, value '3.1e-1'
same = 1 test.man = 00000007B3333 mine.man = 00000007B3333 exp t = 083 m = 083 sig t = 0 m = 0 fpn t = 3.140000e+01 m = 3.140000e+01, value '3.14e+1'
same = 0 test.man = 000000015BA14 mine.man = 000000015BA10 exp t = 09B m = 09B sig t = 0 m = 0 fpn t = 3.140000e+08 m = 3.139999e+08, value '3.14e+8'
same = 0 test.man = 000000069F2BF mine.man = 000000053E57E exp t = 0A1 m = 0A1 sig t = 0 m = 0 fpn t = 3.140000e+10 m = 2.844026e+10, value '3.14e+10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 0FF m = 0FF sig t = 0 m = 0 fpn t = inf m = inf, value '3.14e+100'
same = 1 test.man = 000000020C49C mine.man = 000000020C49C exp t = 07D m = 07D sig t = 0 m = 0 fpn t = 3.140000e-01 m = 3.140000e-01, value '3.14e-1'
same = 1 test.man = 000000006DCAA mine.man = 000000006DCAA exp t = 066 m = 066 sig t = 0 m = 0 fpn t = 3.140000e-08 m = 3.140000e-08, value '3.14e-8'
same = 1 test.man = 00000002C9F92 mine.man = 00000002C9F92 exp t = 05F m = 05F sig t = 0 m = 0 fpn t = 3.140000e-10 m = 3.140000e-10, value '3.14e-10'
same = 1 test.man = 0000000000000 mine.man = 0000000000000 exp t = 000 m = 000 sig t = 0 m = 0 fpn t = 0.000000e+00 m = 0.000000e+00, value '3.14e-100'
Compilation finished successfully.```

14. Well I managed to correct the 3.14e+8 by changing
Code:
`if ( add_half ) fpn = base / 2;`
to
Code:
`if ( add_half ) fpn = one / 2;`
I'm now left with just one to correct

15. Well my latest attempt shows promise, no code that looks like a hack to me, just got 2 inputs providing erronous output
GDB online Debugger | Code, Compile, Run, Debug online C, C++

Popular pages Recent additions