2008-12-29 142 views
37

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

尽管我对C++和Java解决方案特别感兴趣,但我想知道是否有任何语言使它变得特别容易,所以我正在使这个语言不可知论。我很想看到其他语言的一些解决方案。

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

回答

30

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

+3

心灵!浮标和双打的比特尺寸是标准化的,长度,整数等的大小取决于体系结构!您可以使用实现特定类型__int64和__int32(在Windows上)。 – xtofl 2008-12-29 13:18:08

+0

你可以使用我的http://codepad.org/g8OtGEqX。那么你可以使用Integer :: type来代替整数类型。我写了它,因为D常见问题声明C++不能这样做(找到一个至少有N位的类型) – 2008-12-29 14:02:08

+0

代码假设类型的大小非常保守(所以它适用于所有实现,如果你把“long long” )。我想可以写一个更好的版本,其中包含每种基本类型的实际大小列表并决定这些事实。大多数64位系统都有64位长的类型。 – 2008-12-29 14:04:27

6

的Java:谷歌搜索发现,接受多种类型的Sun's forums

明确这个链接(我没有尝试这样做我自己)

long binary = Double.doubleToLongBits(3.14159); 
String strBinary = Long.toBinaryString(binary); 
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); 

奇怪的是,基部64具有1行变换(Convert.ToBase64String),但是基部16需要更多的努力。除非您引用Microsoft.VisualBasic程序,在这种情况下:

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

好两者float和double类(在Java中)有一个toHexString(“浮动”)方法,因此相当多,这将对于进制转换做

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

容易馅饼!

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和扩展 断言。

顺便说一句,cletus建议失败,因为您需要一个“未定义的long long”来覆盖double,无论如何,您需要显示二进制(1或0)表示的内容。

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          [email protected] 
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) 
3

我不得不思考张贴在这里一段时间,因为这可能会激发同胞编码器,以我用C做了坏事。我决定发布它,但请记住:不要在没有适当文档的情况下将这种代码写入任何严肃的应用程序,甚至不要考虑三次。

除了免责声明,我们走吧。

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

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

很遗憾,我们无法直接使用此功能打印我们的浮存变数,所以我们必须搞出一点。对于已经阅读了关于Quake的Carmack's Inverse Square Root技巧的所有人来说,黑客可能看起来很熟悉。这个想法为我们的float变量设置了一个值,然后为我们的长整型变量获得了相同的位掩码。所以我们把f的内存地址转换为一个long *值,并使用该指针将f的位掩码作为一个长符号。如果你打印这个值为无符号长整型,结果会是一团糟,但这些位与原始浮点值相同,所以它并不重要。

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

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

如果您认为此语法糟透了,您说得对。

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和尾数从前奏:

significand 3.14 
0.785 

exponent 3.14 
2 
21

在C:

int fl = *(int*)&floatVar; 

&floatVar将获得ADRESS内存中,然后(int*)将是一个指向此ADRESS内存,最后*得到4字节的值浮点在int中。 然后您可以打印二进制格式或十六进制格式。

2

你可以很容易转换的浮点型变量为int变量(或双长)使用C#这样的代码:

float f = ...; 
unsafe 
{ 
    int i = *(int*)&f; 
} 
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' 
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); 
}