Reputation: 47955
Converting from 0 10000101 01010011000000000000001
to decimal (which is 84.75000762939453125
) works well:
FP: 0 10000101 01010011000000000000001
Fraction: (1.)01010011000000000000001
Exp 10000101: 133
Bias: 133-127=6
Moving by exp: 1010100.11000000000000001
Convert parts to decimal: 84.75000762939453125
Why I'm not able to do the same converting 0 00000001 00000000000000000000001
to decimal (which is (1.1754945E-38
):
FP: 0 00000001 00000000000000000000001
Fraction: (1.)00000000000000000000001
Exp 00000001: 1
Bias: 1-127=-126
Moving by exp: 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Convert parts to decimal: 0.?!?!?!
Can't get 1.1754945E-38
converting binary 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
to decimal.
Where am I wrong?
Upvotes: 5
Views: 318
Reputation: 153537
Where am I wrong?
Couple of problems
Moving by exp
incorrectA 0
should be a 1
.
FP: 0 00000001 00000000000000000000001
Fraction: (1.)00000000000000000000001
Exp 00000001: 1
Bias: 1-127=-126
// wrong
Moving by exp: 0.0000000000 (many zeros omitted) 0000000000000000000000000001
// should be
Moving by exp: 0.0000000000 (many zeros omitted) 0000100000000000000000000001
// ^
OP's reference tool returns 0 for values as great as 0.000000000000000000000000000000000000000000000000000000000000000000012
Inputting 0.0000000000 (many zeros omitted) 0000100000000000000000000001
also reports 0.
A correct conversion of the string "0.0000000000 (many zeros omitted) 0000100000000000000000000001" as a base-2 fraction readily gives OP's expected value.
#include <math.h>
#include <stdio.h>
int main(void) {
char *Moving_by_exp = "0."
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"0000000000"
"00000100000000000000000000001";
char *s = Moving_by_exp;
double x = 0.0;
int power2 = 0;
while (*s) {
power2--;
if (*s == '.') power2 = 0;
else x = x*2 + *s - '0';
s++;
}
printf("%.7e\n", x*pow(2,power2));
printf("%.16e\n", x*pow(2,power2));
}
Ouput
1.1754945e-38
1.1754944909521339e-38
OP's incorrect "0.0000000000 (many zeros omitted) 0000000000000000000000000001" converts to 1.4012985e-45
Upvotes: 2
Reputation: 854
You are not wrong. The tool is wrong.
I found one page (the first that came up when I googled "ieee 754 converter") that has no problems with your number: https://www.h-schmidt.net/FloatConverter/IEEE754.html
I wrote a small C program, which probably contains some unportability, undefined behaviour and obsolete coding practices, but which shows conversions between some relevant floats and ints:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef union {
float f;
int i;
} both;
void printbits(int k) {
int i;
for (i = 0; i < 32; i++) {
if (i == 1 || i == 9)
printf(" ");
if (k & (1<<(31-i)))
printf("1");
else
printf("0");
}
printf("\n");
}
int main() {
printf("sizeof(float) = %ld\n", sizeof(float));
printf("sizeof(int) = %ld\n", sizeof(int));
both u;
u.i = 0x00800001;
printbits(u.i);
printf("%g\n", u.f);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
printf("\n");
u.i = 0x00800000;
printbits(u.i);
printf("%g\n", u.f);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
printf("\n");
u.i = 0x007fffe1;
printf("%g\n", u.f);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
printf("\n");
u.i = 0x42a98001;
printf("%g\n", u.f);
printf("%g\n", 84.75000762939453125);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
printf("\n");
u.f = 1.17549e-38;
printbits(u.i);
printf("%#010x\n", u.i);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
u.f = 1.1754944e-38;
printbits(u.i);
printf("%#010x\n", u.i);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
u.f = 1.1754945e-38;
printbits(u.i);
printf("%#010x\n", u.i);
printf("%d %d\n", fpclassify(u.f), isnormal(u.f));
}
The output (on Ubuntu, compiled with gcc, processor x86) is:
sizeof(float) = 4
sizeof(int) = 4
0 00000001 00000000000000000000001
1.17549e-38
4 1
0 00000001 00000000000000000000000
1.17549e-38
4 1
1.17549e-38
3 0
84.75
84.75
4 1
0 00000000 11111111111111111100001
0x007fffe1
3 0
0 00000001 00000000000000000000000
0x00800000
4 1
Upvotes: 0