views:

4535

answers:

6

I'd like to display the binary (or hexadecimal) representation of a floating point number. I know how to convert by hand (using the method here), but I'm interested in seeing code samples that do the same.

Although I'm particularly interested in the C++ and Java solutions, I wonder if any languages make it particularly easy so I'm making this language agnostic. I'd love to see some solutions in other languages.

EDIT: I've gotten good coverage of C, C++, C#, and Java. Are there any alternative-language gurus out there who want to add to the list?

+10  A: 

C/C++ is easy.

union ufloat {
  float f;
  unsigned u
};

ufloat u1;
u1.f = 0.3f;

Then you just output u1.u. You can adapt this implementation.

Doubles just as easy.

union udouble {
  double d;
  unsigned long u;
}

because doubles are 64 bit.

Java is a bit easier: use Float.floatToRawIntBits() combined with Integer.toBinaryString() and Double.doubleToRawLongBits combined with Long.toBinaryString().

cletus
Mind! The bit sizes of floats and doubles are standardized, the sizes of longs, ints etc... depend on the architecture! You can use implemenetation-specific types __int64 and __int32 (on windows).
xtofl
you can use my http://codepad.org/g8OtGEqX . then you can use Integer< sizeof(double) * CHAR_BIT >::type as the integer type instead. i wrote it because the D faq claimed C++ can't do that (find a type with at least N bits)
Johannes Schaub - litb
the code assumes the size of types very conservatively (so it works on all implementations if you take the "long long" out). i suppose one could write a better version that has a list of the actual sizes of each basic type and decides on those facts. most 64 bit systems have 64bit long types.
Johannes Schaub - litb
I guess the first comment is that sizes are NOT standarized, and in fact they do depend on the architecture. The standard only warrants that sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)<=sizeof(long long), but they could all be just 8 bits. (I am not sure but char could be defined as 8bit)
David Rodríguez - dribeas
@dribeas: char is defined as 1 *byte*, which may not actually be 8 bits (I think it's guaranteed to be at least 8 bits, could be more. Or I could be wrong.). But you are always, always, always guaranteed in C/C++ that sizeof(char) == 1
Jon
You can also do this in D.
Brad Gilbert
+3  A: 

Java: a google search finds this link on Sun's forums

specifically (I haven't tried this myself)

long binary = Double.doubleToLongBits(3.14159);
String strBinary = Long.toBinaryString(binary);
Jason S
Exactly what I was looking for. I searched Google for how to do this in C++ before I posted the question. I should have looked for Java solutions too. :)
Bill the Lizard
+2  A: 

In .NET (including C#), you have BitConverter that accepts many types, allowing access to the raw binary; to get the hex, ToString("x2") is the most common option (perhaps wrapped in a utility method):

    byte[] raw = BitConverter.GetBytes(123.45);
    StringBuilder sb = new StringBuilder(raw.Length * 2);
    foreach (byte b in raw)
    {
        sb.Append(b.ToString("x2"));
    }
    Console.WriteLine(sb);

Oddly, base-64 has a 1-line conversion (Convert.ToBase64String), but base-16 takes more effort. Unless you reference Microsoft.VisualBasic, in which case:

long tmp = BitConverter.DoubleToInt64Bits(123.45);
string hex = Microsoft.VisualBasic.Conversion.Hex(tmp);
Marc Gravell
+2  A: 

Well both the Float and Double class (in Java) have a toHexString('float') method so pretty much this would do for hex conversion

Double.toHexString(42344);
Float.toHexString(42344);

Easy as pie!

Gareth
I'm such a lazy programmer
Gareth
This is pretty good. Double.doubleToLongBits and Float.floatToIntBits are closer to the representation I'm looking for.
Bill the Lizard
A: 

In C++ you can show the binary representation it in this way:

template <class T>
std::bitset<sizeof(T)*8> binary_representation(const T& f)
{
   typedef unsigned long TempType;
   assert(sizeof(T)<=sizeof(TempType));
   return std::bitset<sizeof(T)*8>(*(reinterpret_cast<const TempType*>(&f)));
}

the limit here is due the fact that bitset longer parameter is an unsigned long, so it works up to float, you can use something else than bitset and the extend that assert.

BTW, cletus suggestion fails in the sense that you need an "unsingned long long" to cover a double, anyway you need something that shows the binary (1 or 0) representation.

Gaetano Mendola
+3  A: 

I did it this way:

/*
@(#)File:           $RCSfile: dumpdblflt.c,v $
@(#)Version:        $Revision: 1.1 $
@(#)Last changed:   $Date: 2007/09/05 22:23:33 $
@(#)Purpose:        Print C double and float data in bytes etc.
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2007
@(#)Product:        :PRODUCT:
*/

/*TABSTOP=4*/

#include <stdio.h>
#include "imageprt.h"

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_dumpdblflt_c[];
const char jlss_id_dumpdblflt_c[] = "@(#)$Id: dumpdblflt.c,v 1.1 2007/09/05 22:23:33 jleffler Exp $";
#endif /* lint */

union u_double
{
    double  dbl;
    char    data[sizeof(double)];
};

union u_float
{
    float   flt;
    char    data[sizeof(float)];
};

static void dump_float(union u_float f)
{
    int exp;
    long mant;

    printf("32-bit float: sign: %d, ", (f.data[0] & 0x80) >> 7);
    exp = ((f.data[0] & 0x7F) << 1) | ((f.data[1] & 0x80) >> 7);
    printf("expt: %4d (unbiassed %5d), ", exp, exp - 127);
    mant = ((((f.data[1] & 0x7F) << 8) | (f.data[2] & 0xFF)) << 8) | (f.data[3] & 0xFF);
    printf("mant: %16ld (0x%06lX)\n", mant, mant);
}

static void dump_double(union u_double d)
{
    int exp;
    long long mant;

    printf("64-bit float: sign: %d, ", (d.data[0] & 0x80) >> 7);
    exp = ((d.data[0] & 0x7F) << 4) | ((d.data[1] & 0xF0) >> 4);
    printf("expt: %4d (unbiassed %5d), ", exp, exp - 1023);
    mant = ((((d.data[1] & 0x0F) << 8) | (d.data[2] & 0xFF)) << 8) |
              (d.data[3] & 0xFF);
    mant = (mant << 32) | ((((((d.data[4] & 0xFF) << 8) |
              (d.data[5] & 0xFF)) << 8) | (d.data[6] & 0xFF)) << 8) |
              (d.data[7] & 0xFF);
    printf("mant: %16lld (0x%013llX)\n", mant, mant);
}

static void print_value(double v)
{
    union u_double d;
    union u_float  f;

    f.flt = v;
    d.dbl = v;

    printf("SPARC: float/double of %g\n", v);
    image_print(stdout, 0, f.data, sizeof(f.data));
    image_print(stdout, 0, d.data, sizeof(d.data));
    dump_float(f);
    dump_double(d);
}


int main(void)
{
    print_value(+1.0);
    print_value(+2.0);
    print_value(+3.0);
    print_value( 0.0);
    print_value(-3.0);
    print_value(+3.1415926535897932);
    print_value(+1e126);
    return(0);
}

Running on a SUN UltraSPARC, I got:

SPARC: float/double of 1
0x0000: 3F 80 00 00                                       ?...
0x0000: 3F F0 00 00 00 00 00 00                           ?.......
32-bit float: sign: 0, expt:  127 (unbiassed     0), mant:                0 (0x000000)
64-bit float: sign: 0, expt: 1023 (unbiassed     0), mant:                0 (0x0000000000000)
SPARC: float/double of 2
0x0000: 40 00 00 00                                       @...
0x0000: 40 00 00 00 00 00 00 00                           @.......
32-bit float: sign: 0, expt:  128 (unbiassed     1), mant:                0 (0x000000)
64-bit float: sign: 0, expt: 1024 (unbiassed     1), mant:                0 (0x0000000000000)
SPARC: float/double of 3
0x0000: 40 40 00 00                                       @@..
0x0000: 40 08 00 00 00 00 00 00                           @.......
32-bit float: sign: 0, expt:  128 (unbiassed     1), mant:          4194304 (0x400000)
64-bit float: sign: 0, expt: 1024 (unbiassed     1), mant: 2251799813685248 (0x8000000000000)
SPARC: float/double of 0
0x0000: 00 00 00 00                                       ....
0x0000: 00 00 00 00 00 00 00 00                           ........
32-bit float: sign: 0, expt:    0 (unbiassed  -127), mant:                0 (0x000000)
64-bit float: sign: 0, expt:    0 (unbiassed -1023), mant:                0 (0x0000000000000)
SPARC: float/double of -3
0x0000: C0 40 00 00                                       .@..
0x0000: C0 08 00 00 00 00 00 00                           ........
32-bit float: sign: 1, expt:  128 (unbiassed     1), mant:          4194304 (0x400000)
64-bit float: sign: 1, expt: 1024 (unbiassed     1), mant: 2251799813685248 (0x8000000000000)
SPARC: float/double of 3.14159
0x0000: 40 49 0F DB                                       @I..
0x0000: 40 09 21 FB 54 44 2D 18                           @.!.TD-.
32-bit float: sign: 0, expt:  128 (unbiassed     1), mant:          4788187 (0x490FDB)
64-bit float: sign: 0, expt: 1024 (unbiassed     1), mant: 2570638124657944 (0x921FB54442D18)
SPARC: float/double of 1e+126
0x0000: 7F 80 00 00                                       ....
0x0000: 5A 17 A2 EC C4 14 A0 3F                           Z......?
32-bit float: sign: 0, expt:  255 (unbiassed   128), mant:                0 (0x000000)
64-bit float: sign: 0, expt: 1441 (unbiassed   418), mant:      -1005281217 (0xFFFFFFFFC414A03F)
Jonathan Leffler