3

I'm trying to write an algorithm to convert a hexadecimal number to a floating point number and vice versa. This is part of an assignment, the program is supposed to receive either an 8 digit hexadecimal number that starts with '0x' or a floating point number, and using the computer's 'built in IEEE 754 capabilities' convert the number to hex or float. The code should be in C.

My approach is the following. Store the input by the user as a string. Pass the input char array to a method that checks if it's a hexadecimal number by checking the first two positions of the array, which should be 0 and X (assume all hex numbers are passed this way). If this is the case, then I check that the hex is in the appropriate form, i.e not too many digits or numbers outside the 0-15 range (also considering the ABCDEF convention).

So, my problem is, I don't know how to turn this array back into a number that I can use to convert to floating point. I thought about using sscanf to turn it back into a float but I don't know enough C and haven't found any good sources online

Can somebody point me in the right direction? I also thought about storing the user input both as a string and a number at the same time, but I am not sure if this is possible.

Here are the two form checking functions and the incomplete main method:

int is_hex(char arr[])
{
    if (arr[0] == '0' && (arr[1] == 'x' || arr[1] == 'X')) {
        return 1;
    }
    return 0;
}

int check_if_good(char arr[])
{
    if (is_hex(arr)) {
        int len = strlen(arr);
        for (int i = 2; i < len; i++) {
            if ((arr[i] > 'f' && arr[i] <= 'z') || (arr[i] > 'F' && arr[i] <= 'Z')) {
                return 0;
            }
        }
    }

    return 1;
}

int main(int argc, const char * argv[])
{
    float x;
    char input[30];
    scanf("%s", input);
    printf("%s", input);
    return 0;
}

If somebody could also tell me the basics of what '%x' means i would really appreciate it. From what I understand it lets me collect numbers in hexadecimal form, but can i store them in ints and floats? Thank you very much for your help.

--Edit: Extra code for floris. I'm trying to solve this problem without using any extra libraries, so you can't use the stdint lib.

char input[30];
scanf("%s", input);
if(check_if_good(input)){  //Ignore this if-statement.
    printf("Input is in hex form");
}
int num = convert_hex_string(input); // this function works perfectly. It return the int form of the hex.
double f = *((double*)&num);
printf("%f\n", f);
macalaca
  • 988
  • 1
  • 13
  • 31

4 Answers4

16

If you actually want to know what floating point number is represented by a particular hex string, you can convert the string to an integer, then look at the address pretending that it contains a floating point number. Here's how that would work:

#include <stdint.h>
#include <stdio.h>

int main(void) {
  char myString[]="0x3f9d70a4";
  uint32_t num;
  float f;
  sscanf(myString, "%x", &num);  // assuming you checked input
  f = *((float*)&num);
  printf("the hexadecimal 0x%08x becomes %.3f as a float\n", num, f);
}

This produces as output

the hexadecimal 0x3f9d70a4 becomes 1.230 as a float

As expected. See my answer to your other question about a related topic for more details.

It should also be easy to see how you can do the above in reverse - start with a floating point number, and get the hexadecimal representation.

Community
  • 1
  • 1
Floris
  • 45,857
  • 6
  • 70
  • 122
  • Hey Floris! I'm trying to implement your code without the library. Everything works fine, I was able to convert a hex string to its integer value by looping through the contents and doing a bunch of multiplication. But, now when I try to print its float representation I always get 0.0000, do you know what might be wrong? Thanks! – macalaca Jan 27 '14 at 23:43
  • Bit hard to guess... can you show the key lines that reproduce your problem? `` just makes sure that the `uint32_t` type exists and is four bytes long - you can see whether `sizeof(int) == 4` in which case you can just use `int` and you won't need `stdint.h`. Otherwise, use `long int` instead. But show some code. If needed, edit your question. – Floris Jan 28 '14 at 00:20
  • Thanks for adding the code; the issue is now really simple. You are using `double` (which is an 8 byte number) instead of `float` - so you are not looking at the whole number. In fact you're lucky that this didn't just crash... If you just replace `double` with `float` in your code, all will be well (assuming that `sizeof(int)==4`). The header file (not a library!) that I was including just guarantees the size of the type, but if you know your compiler it's easy to figure out how big an `int` is, and then you don't need `` - and won't have to use `uint32_t`. – Floris Jan 28 '14 at 01:22
  • considering I'm converting a hex to an int, wouldn't my integer be composed by 32 bits since the hex is of this size, which is then turned to IEEE 754 by converting it to a float? So, what should in case the size of the int is much larger than 4? This live help is the best thing to ever happen to me. Thank you. – macalaca Jan 28 '14 at 01:30
  • 1
    No the `int` is still just four **bytes** (32 **bits**) long (although it may represent a number like 12345678). The `double` is eight **bytes** long. Use `float`. – Floris Jan 28 '14 at 01:31
  • I really don't mean to bother you anymore, but even with the double's changed to float's the program still outputs 0.0000 for all inputs. Maybe if you try running the code it will fail. I'll ask my prof tomorrow and if I figure it out I'll post it here. Maybe it's my compiler, I'm writing C in xcode. Thanks for everything! – macalaca Jan 28 '14 at 03:33
  • Check `sizeof(int)` and `sizeof(float)` - both should be 4. – Floris Jan 28 '14 at 04:44
  • 1
    Sorry to say, while this was an okay technique back in the day, and may still work, it runs afoul of "[strict aliasing](https://stackoverflow.com/questions/98650)", and can't be recommended any more. – Steve Summit Sep 01 '22 at 21:52
2

If you are permitted to use library functions, try atoi(arr) or sscanf(arr+2, "%x", &num)

If you want to parse the string manually, think about how you'd convert a decimal number. For example, converting "2987" to an integer...

int n = 0;
n += 1000 * 2;
n += 100  * 9;
n += 10   * 8;
n += 1    * 7;

Now apply the technique to hexadecimal. Here is a code snippet to do a single ascii character:

int char_to_int(char c) {
   if (c >= '0' && c <= '9') return c - '0';
   if (c >= 'A' && c <= 'F') return c - 'A' + 10;
   return 0; /* oops, something else... */
}
Alcamtar
  • 1,478
  • 13
  • 19
0

You'll need to use either multiplication or bit operations. After you do your bounds/hex checking you described, do something like this:

float x = 0;
for(i=0;i<8;i++)
{
 x += getDecimalValue(inputArray[i+2]) << (4*(7-i))
}

This is untested code & you will need to do the conversion from char to decimal value (A=10, B=11 ect). That bitwise operation is the same as multiplying the decimal equivalent of the hex character by 2^numberOfBits. This answer is assuming the leftmost hex is the most significant (Big endian), reverse the operation for little endianess.

George
  • 416
  • 3
  • 11
0

If the input is in the form: "0x......" then

float f;
long l;

l = strtol(input, (char**)NULL, 16);
f = (float)l;

printf("%f", f);

valter

  • No. This converts the *value* of the hexadecimal number to `float`. The OP wants to use the raw bits. For example, they want `0x40480000` to convert to `3.125`, not `1078460416.0`. – Steve Summit Sep 01 '22 at 21:48