1

I cannot figure out how to convert the value of a referenced float pointer when it is referenced from an integer casted into a float pointer. I'm sorry if I'm wording this incorrectly. Here is an example of what I mean:

#include <stdio.h>

main() {
    int i;
    float *f;

    i = 1092616192;

    f = (float *)&i;

    printf("i is %d and f is %f\n", i, *f);
}

the output for f is 10. How did I get that result?

Jose Ortiz
  • 311
  • 1
  • 3
  • 14

3 Answers3

4

Normally, the value of 1092616192 in hexadecimal is 0x41200000.

In floating-point, that will give you:

sign = positive (0b)
exponent = 130, 2^3 (10000010b)
significand = 2097152, 1.25 (01000000000000000000000b)

2^3*1.25 = 8 *1.25 = 10

To explain the exponent part uses an offset encoding, so you have to subtract 127 from it to get the real value. 130 - 127 = 3. And since this is a binary encoding, we use 2 as the base. 2 ^ 3 = 8.

To explain the significand part, you start with an invisible 'whole' value of 1. the uppermost (leftmost) bit is half of that, 0.5. The next bit is half of 0.5, 0.25. Because only the 0.25 bit and the default '1' bit is set, the significand represents 1 + 0.25 = 1.25.

DeftlyHacked
  • 405
  • 2
  • 9
  • UV for the genuine effort at dissecting the float format... you should also link the wikipedia page. – chqrlie Aug 19 '16 at 04:08
  • I just updated the post to contain how I calculated the value. I would have linked the wiki page, but the explanation of it there is confusing as hell, and I figured I could explain it better. – DeftlyHacked Aug 19 '16 at 04:11
  • This is a much better one: https://en.wikipedia.org/wiki/Single-precision_floating-point_format – chqrlie Aug 19 '16 at 04:12
  • I'm a little confused on how you worked out the significand binary (01000000000000000000000b) to result you in 1.25. can you explain a little more? – Jose Ortiz Aug 19 '16 at 04:29
  • In floating-point, there is an implicit uppermost 24th bit. if the number begins with a 0 (eg. 0.5) then it is called 'denormalized'; otherwise it's 1. The value can be calculated as a summation of values for each bit for 2^(n-24), where 'n' is the bit number. Since this number is normalized, this evaluates to (1*2^(24-24)) + (0*2^(24-23)) + (1*2^(24-22)) = (1*2^0) + (0*2^-1) + (1*2^-2) = (1 * 1) + (0 * 0.5) + (1 * 0.25) = 1 + 0 + 0.25 = 1.25 – DeftlyHacked Aug 19 '16 at 04:41
  • @DeftlyHacked's Thank you very much for the explanation! Wiki needs to have explanations like this. I very much appreciate you're reply. I need to reword my problem so that way it could be of better reference to whoever needs this in the future. – Jose Ortiz Aug 19 '16 at 12:39
2

What you are trying to do is called type-punning. It should be done via a union, or using memcpy() and is only meaningful on an architecture where sizeof(int) == sizeof(float) without padding bits. The result is highly dependent on the architecture: byte ordering and floating point representation will affect the reinterpreted value. The presence of padding bits would invoke undefined behavior as the representation of float 15.0 could be a trap value for type int.

Here is how you get the number corresponding to 15.0:

#include <stdio.h>

int main(void) {
    union {
        float f;
        int i;
        unsigned int u;
    } u;

    u.f = 15;

    printf("re-interpreting the bits of float %.1f as int gives %d (%#x in hex)\n",
           u.f, u.i, u.u);

    return 0;
}

output on an Intel PC:

re-interpreting the bits of float 15.0 as int gives 1097859072 (0x41700000 in hex)
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • DV because this doesn't answer the mc's question, "The output for f is 10. How did I get that result?" – DeftlyHacked Aug 19 '16 at 06:34
  • @DeftlyHacked OP also asked in comments "How could I change i, to get 15 as a value of f?" – M.M Aug 20 '16 at 00:24
  • Well, to deconstruct it; a positive value would mean the sign bit would be 0. For the next step, we need to figure out what exponent to use. For that, we just use the floor (integer part) of the log₂(15), which is 3. Because of the offset encoding, we then add 127, giving us an exponent field of 10000010b. Lastly, we need to figure out the significand (mantissa part). 2^3 = 8, and 15 / 8 = 1.875. 1 + 0.5 + 0.25 + 0.125 = 1.875; and '1' is implied, so we end up with 11100000000000000000000b. The full code 01000001011100000000000000000000b in hex is 0x41700000, and in decimal is 1097859072. – DeftlyHacked Aug 20 '16 at 03:28
  • @DeftlyHacked: you are absolutely right, and your answer for the first question nails it. I took a pragmatic approach for the second question which is trivial to generalize to pretty much any number, and does not assume IEEE-754, nor any special endianness. It only assumes no padding bits and `sizeof(int) == sizeof(float)` and to some extent 2s complement integer representation. – chqrlie Aug 20 '16 at 10:39
0

You are trying to predict the consequence of an undefined activity - it depends on a lot of random things, and on the hardware and OS you are using.

Basically, what you are doing is throwing a glass against the wall and getting a certain shard. Now you are asking how to get a differently formed shard. well, you need to throw the glass differently against the wall...

Aganju
  • 6,295
  • 1
  • 12
  • 23