Bill the Lizard
Bill the Lizard

Reputation: 405755

How do I display the binary representation of a float or double?

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?

Upvotes: 47

Views: 63196

Answers (13)

cletus
cletus

Reputation: 625077

C/C++ is easy.

union ufloat {
  float f;
  unsigned u;
};

ufloat u1;
u1.f = 0.3f;

Then you just output u1.u.

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().

Upvotes: 40

quantum
quantum

Reputation: 3830

Python:

Code:

import struct

def float2bin(number, hexdecimal=False, single=False):
    bytes = struct.pack('>f' if single else '>d', number)
    func, length = (hex, 2) if hexdecimal else (bin, 8)
    byte2bin = lambda byte: func(ord(byte))[2:].rjust(length, '0')
    return ''.join(map(byte2bin, bytes))

Sample:

>>> float2bin(1.0)
'0011111111110000000000000000000000000000000000000000000000000000'
>>> float2bin(-1.0)
'1011111111110000000000000000000000000000000000000000000000000000'
>>> float2bin(1.0, True)
'3ff0000000000000'
>>> float2bin(1.0, True, True)
'3f800000'
>>> float2bin(-1.0, True)
'bff0000000000000'

Upvotes: 3

MaxPlankton
MaxPlankton

Reputation: 1248

For future reference, C++ 2a introduce a new function template bit_cast that does the job.

template< class To, class From >
constexpr To bit_cast(const From& from) noexcept;

We can simply call,

float f = 3.14;
std::bit_cast<int>(f);

For more details, see https://en.cppreference.com/w/cpp/numeric/bit_cast

Upvotes: 1

Massimiliano
Massimiliano

Reputation: 8032

Apparently nobody cared to mention how trivial is to obtain hexadecimal exponent notation, so here it is:

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    // C++11 manipulator
    cout << 23.0f << " : " << std::hexfloat << 23.0f << endl;
    // C equivalent solution
    printf("23.0 in hexadecimal is: %A\n", 23.0f);
}

Upvotes: 8

Jason S
Jason S

Reputation: 189656

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);

Upvotes: 7

bslima
bslima

Reputation: 1145

In C:

int fl = *(int*)&floatVar;

&floatVar would get the adress memory then (int*) would be a pointer to this adress memory, finally the * to get the value of the 4 bytes float in int. Then you can printf the binary format or hex format.

Upvotes: 33

Ivan Kochurkin
Ivan Kochurkin

Reputation: 4481

You can easy convert float variable to int variable (or double to long) using such code in C#:

float f = ...;   
unsafe
{
    int i = *(int*)&f;
}

Upvotes: 2

Zouppen
Zouppen

Reputation: 1264

In Haskell, there is no internal representation of floating points accessible. But you can do binary serialiazation from many formats, including Float and Double. The following solution is generic to any type that has instance of Data.Binary supports:

module BinarySerial where

import Data.Bits
import Data.Binary
import qualified Data.ByteString.Lazy as B

elemToBits :: (Bits a) => a -> [Bool]
elemToBits a = map (testBit a) [0..7]

listToBits :: (Bits a) => [a] -> [Bool]
listToBits a = reverse $ concat $ map elemToBits a

rawBits :: (Binary a) => a -> [Bool]
rawBits a = listToBits $ B.unpack $ encode a

Conversion can be done with rawBits:

rawBits (3.14::Float)

But, if you need to access the float value this way, you are probably doing something wrong. The real question might be How to access exponent and significand of a floating-point number? The answers are exponent and significand from Prelude:

significand 3.14
0.785

exponent 3.14
2

Upvotes: 3

Ville Salonen
Ville Salonen

Reputation: 2654

I had to think about posting here for a while because this might inspire fellow coders to do evil things with C. I decided to post it anyway but just remember: do not write this kind of code to any serious application without proper documentation and even then think thrice.

With the disclaimer aside, here we go.

First write a function for printing for instance a long unsigned variable in binary format:

void printbin(unsigned long x, int n)
{
  if (--n) printbin(x>>1, n);
  putchar("01"[x&1]);
}

Unfortunately we can't directly use this function to print our float variable so we'll have to hack a little. The hack probably looks familiar to everyone who have read about Carmack's Inverse Square Root trick for Quake. The idea is set a value for our float variable and then get the same bit mask for our long integer variable. So we take the memory address of f, convert it to a long* value and use that pointer to get the bit mask of f as a long unsigned. If you were to print this value as long unsigned, the result would be a mess, but the bits are the same as in the original float value so it doesn't really matter.

int main(void)
{
  long unsigned lu;
  float f = -1.1f;

  lu = *(long*)&f;
  printbin(lu, 32);
  printf("\n");
  return 0;
}

If you think this syntax is awful, you're right.

Upvotes: 3

Jonathan Leffler
Jonathan Leffler

Reputation: 753695

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)

Upvotes: 5

Gaetano Mendola
Gaetano Mendola

Reputation: 1394

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.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062770

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);

Upvotes: 6

Gareth
Gareth

Reputation: 2200

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!

Upvotes: 3

Related Questions