Forums: » Register « |  Free Tools |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support |

New Free Tools on Dev Shed!

#1
November 1st, 2008, 11:08 AM
 kenshinofkin
Registered User

Join Date: Jul 2008
Posts: 5
Time spent in forums: 41 m 54 sec
Reputation Power: 0
Printing a float as a hex number

hello all

If a user enters a floatint point number like 10.1, I want to print out the hex number in floating point. The %X specifer allows for an int to be printed as a hex number and I heard you could do the samething with floating point numbers with casting and pointers but I can't seem to figure it out. Anyone have any ideas? Thanks

#2
November 1st, 2008, 11:25 AM
 sizablegrin

Join Date: Jun 2005
Posts: 5,964
Time spent in forums: 2 Months 3 Weeks 2 Days 12 h 47 m 19 sec
Warnings Level: 10
Number of bans: 1
Reputation Power: 4851
Convert the whole number and the fraction to hex separately, then recombine.

If you mean "express the binary pattern of the floating point representation in hex digits", that's a different story.
__________________
Write no code whose complexity leaves you wondering what the hell you did.
Politically Incorrect DaWei on Pointers Grumpy on Exceptions

#3
November 1st, 2008, 11:31 AM
 kenshinofkin
Registered User

Join Date: Jul 2008
Posts: 5
Time spent in forums: 41 m 54 sec
Reputation Power: 0
Quote:
 Originally Posted by sizablegrin Convert the whole number and the fraction to hex separately, then recombine. If you mean "express the binary pattern of the floating point representation in hex digits", that's a different story.

I mean if 10.1 is entered the floating point Hex number would be 4121999A.

#4
November 1st, 2008, 11:44 AM
 Lux Perpetua
Contributing User

Join Date: Feb 2004
Location: San Francisco Bay
Posts: 1,939
Time spent in forums: 1 Month 1 Week 3 h 27 m 29 sec
Reputation Power: 1312
So something like this?
Code:
```#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
float a = 10.1;

printf("%X\n", *(int *)&a);

return 0;
}```
clifford agrees: I did not ignore your post, I just took several hours typing mine!

#5
November 1st, 2008, 11:56 AM
 kenshinofkin
Registered User

Join Date: Jul 2008
Posts: 5
Time spent in forums: 41 m 54 sec
Reputation Power: 0
Quote:
 Originally Posted by Lux Perpetua So something like this? Code: ```#include #include int main(int argc, char **argv) { float a = 10.1; printf("%X\n", *(int *)&a); return 0; }```

YES!!! Thank you that is what I was looking for! Thank you.
clifford agrees: It probably is, but beware of the circumstances in which it won't work (see below)

#6
November 1st, 2008, 01:43 PM
 clifford
Contributing User

Join Date: Aug 2003
Location: UK
Posts: 4,975
Time spent in forums: 1 Month 4 Days 5 h 13 m 15 sec
Reputation Power: 1801
If you simply cast a float to an integer type it performs a conversion that modifies the bit pattern, which defeats the purpose. So the trick is to take the address of the float, cast the pointer to an integer pointer (which has no effect on the bit pattern of the data), and then dereference it so that the data is interpreted as an integer but witout changing the bit pattern.

You do have to be careful however to ensure that the floating point type and the integer type have the same bit-width. Doing that portably requires some thought, but basically, if we assume that both float and long are both the same width, which is generally true on the most commonly used platforms, then:

Code:
```float f = 10.1f ;
printf( "0x%8.8XL\n", *((long*)&f) ) ;```

However, to do that with a double, requires that your compiler support a 64bit integer type, which is not a given. Moreover printing a long double may prove difficult as there may not be an integer type of the same width.

A more flexible method is to take the address of the FP value, cast it to a char* and iterate through it as a char array using the size of the FP type as a limit and outputting each character as a hex digit pair. This may display in a different byte order than the previous method depending on your processor, but you could choose to display from high to low address or vice versa. In the end it does not really matter, so long as you know what you are looking at. IEEE754 does not actually specify a byte order in any case.

The char array method is an ideal application for a C++ template function so that it will handle any FP type. In fact it will allow you to display a hex dump of any type, including structures and classes.

Example:
C++ Code:
 Original - C++ Code
``` #include <string>#include <sstream>#include <iomanip>#include <iostream> bool isLittleEndian(){    static bool little_endian ;    static bool endian_checked = false ;    // runtime endianness check (once only)    if( !endian_checked )    {        const short endian_test_pattern = 0x00ff ;        little_endian = *(reinterpret_cast<const char*>(&endian_test_pattern)) == '\xff' ;        endian_checked = true ;    }     return little_endian ;} template <class T> std::string type_to_hex( const T arg ){    std::ostringstream hexstr ;    const char* addr = reinterpret_cast<const char*>(&arg) ;     hexstr << "0x" ;    hexstr << std::setw(2) << std::setprecision(2) << std::setfill('0') << std::hex ;     if( isLittleEndian() )    {        for( int b = sizeof(arg) - 1; b >= 0; b-- )        {            hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;        }    }    else    {        for( int b = 0; b < sizeof(arg); b++ )        {            hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;        }    }    return hexstr.str() ;} using std::cout ;using std::endl ;int main(){    const int i = 123 ;    const float f = 0.123f ;    const double d = 0.123 ;    const long double ld = 0.123L ;    const struct{ int x; int y; } s = { 123, 321 } ;     cout << "i:  " << type_to_hex( i ) << endl ;    cout << "f:  " << type_to_hex( f ) << endl ;    cout << "d:  " << type_to_hex( d ) << endl ;    cout << "ld: " << type_to_hex( ld ) << endl ;    cout << "s:  " << type_to_hex( s ) << endl ;     cout << "f using cast method: 0x" << std::hex << *((int*)&f) << endl ;}
```

In Win32 using VC++ 2008 this outputs:

Code:
```i:  0x00007b
f:  0x3dfbe76d
d:  0x3fbf7ced916872b0
ld: 0x3fbf7ced916872b0
s:  0x0001410007b
f using cast method: 0x3dfbe76d```

Clifford
xlordt agrees: Well said.. I actually learned something new :P

Last edited by clifford : November 1st, 2008 at 02:30 PM. Reason: endian check in a spearate function

#7
November 2nd, 2008, 10:09 PM
 kenshinofkin
Registered User

Join Date: Jul 2008
Posts: 5
Time spent in forums: 41 m 54 sec
Reputation Power: 0
Quote:
Originally Posted by clifford
If you simply cast a float to an integer type it performs a conversion that modifies the bit pattern, which defeats the purpose. So the trick is to take the address of the float, cast the pointer to an integer pointer (which has no effect on the bit pattern of the data), and then dereference it so that the data is interpreted as an integer but witout changing the bit pattern.

You do have to be careful however to ensure that the floating point type and the integer type have the same bit-width. Doing that portably requires some thought, but basically, if we assume that both float and long are both the same width, which is generally true on the most commonly used platforms, then:

Code:
```float f = 10.1f ;
printf( "0x%8.8XL\n", *((long*)&f) ) ;```

However, to do that with a double, requires that your compiler support a 64bit integer type, which is not a given. Moreover printing a long double may prove difficult as there may not be an integer type of the same width.

A more flexible method is to take the address of the FP value, cast it to a char* and iterate through it as a char array using the size of the FP type as a limit and outputting each character as a hex digit pair. This may display in a different byte order than the previous method depending on your processor, but you could choose to display from high to low address or vice versa. In the end it does not really matter, so long as you know what you are looking at. IEEE754 does not actually specify a byte order in any case.

The char array method is an ideal application for a C++ template function so that it will handle any FP type. In fact it will allow you to display a hex dump of any type, including structures and classes.

Example:
C++ Code:
 Original - C++ Code
``` #include <string>#include <sstream>#include <iomanip>#include <iostream> bool isLittleEndian(){    static bool little_endian ;    static bool endian_checked = false ;    // runtime endianness check (once only)    if( !endian_checked )    {        const short endian_test_pattern = 0x00ff ;        little_endian = *(reinterpret_cast<const char*>(&endian_test_pattern)) == '\xff' ;        endian_checked = true ;    }     return little_endian ;} template <class T> std::string type_to_hex( const T arg ){    std::ostringstream hexstr ;    const char* addr = reinterpret_cast<const char*>(&arg) ;     hexstr << "0x" ;    hexstr << std::setw(2) << std::setprecision(2) << std::setfill('0') << std::hex ;     if( isLittleEndian() )    {        for( int b = sizeof(arg) - 1; b >= 0; b-- )        {            hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;        }    }    else    {        for( int b = 0; b < sizeof(arg); b++ )        {            hexstr << static_cast<unsigned>(*(addr+b) & 0xff) ;        }    }    return hexstr.str() ;} using std::cout ;using std::endl ;int main(){    const int i = 123 ;    const float f = 0.123f ;    const double d = 0.123 ;    const long double ld = 0.123L ;    const struct{ int x; int y; } s = { 123, 321 } ;     cout << "i:  " << type_to_hex( i ) << endl ;    cout << "f:  " << type_to_hex( f ) << endl ;    cout << "d:  " << type_to_hex( d ) << endl ;    cout << "ld: " << type_to_hex( ld ) << endl ;    cout << "s:  " << type_to_hex( s ) << endl ;     cout << "f using cast method: 0x" << std::hex << *((int*)&f) << endl ;}
```

In Win32 using VC++ 2008 this outputs:

Code:
```i:  0x00007b
f:  0x3dfbe76d
d:  0x3fbf7ced916872b0
ld: 0x3fbf7ced916872b0
s:  0x0001410007b
f using cast method: 0x3dfbe76d```

Clifford

Wow thank you clifford. I was wondering how the convertion worked. Thanks for the post you showed me some interesting things. Thanks again

#8
November 3rd, 2008, 03:14 AM
 clifford
Contributing User

Join Date: Aug 2003
Location: UK
Posts: 4,975
Time spent in forums: 1 Month 4 Days 5 h 13 m 15 sec
Reputation Power: 1801
Quote:
 Originally Posted by kenshinofkin Wow thank you clifford.
You are welcome, but there really s no need to re-quote the entire previous post! It is already there for all to see. Quoting is intended for making reference to out-of-order posts or particular points to make it clear what you are referring to. If you are merely referring to the previous post in its entirity, then no quote is needed.

My scroll wheel hurts!

 Viewing: Dev Shed Forums > Programming Languages > C Programming > Printing a float as a hex number