如何显示float或double的二进制表示?

时间:2008-12-29 13:08:54

标签: language-agnostic floating-point

我想显示浮点数的二进制(或十六进制)表示。我知道如何手动转换(使用方法here),但我有兴趣看到相同的代码示例。

虽然我对C ++和Java解决方案特别感兴趣,但我想知道是否有任何语言让它变得特别容易,所以我正在使这个语言无关。我很想看到其他语言的解决方案。

编辑:我已经很好地报道了C,C ++,C#和Java。是否有任何想要添加到列表中的替代语言专家?

13 个答案:

答案 0 :(得分:31)

C / C ++很容易。

union ufloat {
  float f;
  unsigned u;
};

ufloat u1;
u1.f = 0.3f;

然后你输出u1.u。您可以调整this implementation

双打也很容易。

union udouble {
  double d;
  unsigned long u;
}

因为双打是64位。

Java更容易:使用Float.floatToRawIntBits()结合Integer.toBinaryString()Double.doubleToRawLongBits结合Long.toBinaryString()

答案 1 :(得分:25)

在C:

int fl = *(int*)&floatVar;

&floatVar将获得地址内存,然后(int*)将成为指向此地址内存的指针,最后*将获取4字节的值浮点数为int。 然后你可以打印二进制格式或十六进制格式。

答案 2 :(得分:7)

Java:谷歌搜索在Sun's forums

上找到此链接

具体(我自己没试过)

long binary = Double.doubleToLongBits(3.14159);
String strBinary = Long.toBinaryString(binary);

答案 3 :(得分:6)

在.NET(包括C#)中,你有BitConverter接受许多类型,允许访问原始二进制文件;要获得十六进制,ToString("x2")是最常见的选项(可能包含在实用程序方法中):

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

奇怪的是,base-64有1行转换(Convert.ToBase64String),但base-16需要更多努力。除非你引用Microsoft.VisualBasic,在这种情况下:

long tmp = BitConverter.DoubleToInt64Bits(123.45);
string hex = Microsoft.VisualBasic.Conversion.Hex(tmp);

答案 4 :(得分:4)

我是这样做的:

/*
@(#)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);
}

在SUN UltraSPARC上运行,我得到了:

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)

答案 5 :(得分:3)

那么Float和Double类(在Java中)都有一个toHexString('float')方法,这对于十六进制转换非常重要

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

简单就是馅饼!

答案 6 :(得分:3)

我不得不考虑在这里发布一段时间,因为这可能激发其他编码员用C做邪恶的事情。我决定发布它但是只记得:如果没有适当的文档,不要将这种代码写入任何严肃的应用程序甚至那时思考三次。

抛开免责声明,我们走了。

首先编写一个打印函数,例如二进制格式的长无符号变量:

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

不幸的是我们不能直接使用这个函数来打印我们的float变量,所以我们不得不破解一下。对于那些阅读过Carmack's Inverse Square Root Quake技巧的人来说,黑客看起来很熟悉。这个想法是为我们的浮点变量设置一个值,然后为我们的长整数变量获得相同的位掩码。因此我们取f的内存地址,将其转换为long *值,并使用该指针将f的位掩码作为长无符号。如果要将此值打印为无符号长度,则结果将是一团糟,但这些位与原始浮点值中的位相同,因此它并不重要。

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

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

如果您认为这种语法很糟糕,那就没错了。

答案 7 :(得分:3)

在Haskell中,没有可访问浮点的内部表示。但是你可以从多种格式进行二进制序列化,包括Float和Double。以下解决方案对于具有Data.Binary支持实例的任何类型都是通用的:

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

可以使用rawBits进行转换:

rawBits (3.14::Float)

但是,如果你需要以这种方式访问​​浮点值,你可能做错了。真正的问题可能是如何访问浮点数的指数和有效数?答案是exponent和来自Prelude的有效数字:

significand 3.14
0.785

exponent 3.14
2

答案 8 :(得分:3)

<强>的Python:

代码:

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:].ljust(length, '0')
    return ''.join(map(byte2bin, bytes))

样品:

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

答案 9 :(得分:3)

显然没有人会提到获得十六进制指数符号是多么微不足道,所以这里是:

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

答案 10 :(得分:2)

您可以使用C#中的代码轻松地将float变量转换为int变量(或double到long):

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

答案 11 :(得分:0)

在C ++中,您可以用这种方式显示二进制表示:

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

这里的限制是因为bitset较长的参数是unsigned long, 所以它可以浮动,你可以使用比bitset和extend更多的东西 断言。

顺便说一下,在你需要一个“未加长的长”来覆盖双重的意义上,cletus建议失败了,无论如何你需要一些显示二进制(1或0)表示的东西。

答案 12 :(得分:0)

为了将来参考,C ++ 2a引入了一个新的功能模板bit_cast

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

我们可以简单地打电话给

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

有关更多详细信息,请参见https://en.cppreference.com/w/cpp/numeric/bit_cast