Convert a hexadecimal to a float and viceversa in C

42,214

Solution 1

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.

Solution 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... */
}

Solution 3

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

Solution 4

To convert a string of hexadecimal or floating point characters in to a float:

float StringToFloat(const char *s) {
  // OP's is_hex()
  if ((*s == '0') && ((*s == 'X') || (*s == 'x'))) {
    unsigned long ul = strtoul(d, NULL, 16);
    return  (float) ul;
  }
  double d = atof(s, NULL);
  return (float) d;
}
// Error handling omitted.

To convert a float to a string of hexadecimal characters:

// return 1 on error
int StringToFloat(char *dest, float x) {
  float y = roundf(x);
  if ((x != y) || (y >= 4294967296.0f) || (y < 0.0f)) return 1;
  sprintf(dest, "0x%lx", (unsigned long) y);
  return 0;
}

To convert a string of hexadecimal characters into a float or unsigned long without library functions.
(Does not assume ASCII).

// Substitute unsigned long for float as desired.
// Error return handing is then different.
float HexStringToFloat(const char *s) {
  if ((*s != '0') || ((*s != 'X') && (*s != 'x'))) {
    return NAN;  // Not-a-number macro from math.h
  }
  float x = 0;
  int ch;
  while ((ch = *s++) != '\0') {
    static const char HexDigit[] = "0123456789ABCDEFabcdef";
    int i = 0;
    while (1) {
      if (HexDigit[i] == '\0') return NAN;
      if (HexDigit[i] == ch) break;
      i++; 
    }
    if (i >= 16) i -= 6;
    x *= 16;
    x += i;
  }
  return x;
}
Share:
42,214
macalaca
Author by

macalaca

Love to learn. Never stop. Much to see and experience.

Updated on January 28, 2020

Comments

  • macalaca
    macalaca about 4 years

    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);
    
  • chux - Reinstate Monica
    chux - Reinstate Monica over 10 years
    arr+2 can simple be arr. "%x" will consume the "0x".
  • luser droog
    luser droog over 10 years
    subtracting 48 takes '0'(0x30 or 48) to 0; if >9, then subtract 7 to take 'A'(65==48+10+7) to 10.
  • macalaca
    macalaca about 10 years
    Hey Floris! I'm trying to implement your code without the <stdint.h> 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!
  • Floris
    Floris about 10 years
    Bit hard to guess... can you show the key lines that reproduce your problem? <stdint.h> 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
    Floris about 10 years
    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 <stdint.h> - and won't have to use uint32_t.
  • macalaca
    macalaca about 10 years
    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.
  • Floris
    Floris about 10 years
    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.
  • macalaca
    macalaca about 10 years
    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!
  • Floris
    Floris about 10 years
    Check sizeof(int) and sizeof(float) - both should be 4.