markzzz
markzzz

Reputation: 47955

What's wrong on this floating point to decimal conversion?

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

Answers (2)

chux
chux

Reputation: 153537

Where am I wrong?

Couple of problems

Moving by exp incorrect

A 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
//                                                   ^

Web site incorrect

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

Arndt Jonasson
Arndt Jonasson

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

Related Questions