如何显示浮点数或双精度浮点数的二进制表示forms?

我想显示一个浮点数的二进制(或hex)表示。 我知道如何手工转换(使用这里的方法),但我有兴趣看到相同的代码示例。

虽然我对C ++和Java解决scheme特别感兴趣,但是我想知道是否有任何语言使得它特别容易,所以我使这种语言是不可知的 。 我很想看到其他语言的一些解决scheme。

编辑:我已经得到了很好的C,C ++,C#和Java的覆盖面。 有没有可供select的替代语言专家?

C / C ++很容易。

union ufloat { float f; unsigned u; }; ufloat u1; u1.f = 0.3f; 

然后你只输出u1.u 你可以调整这个实现 。

双打一样容易。

 union udouble { double d; unsigned long u; } 

因为双打是64位。

Java更简单一些:将Float.floatToRawIntBits()与Integer.toBinaryString()结合使用,将Double.doubleToRawLongBits与Long.toBinaryString()结合使用。

在C:

 int fl = *(int*)&floatVar; 

&floatVar会得到地址内存然后(int*)将是一个指向这个地址内存的指针,最后*得到4个字节的浮点数int的值。 然后你可以打印二进制格式或hex格式。

在.NET(包括C#)中,你有BitConverter接受许多types,允许访问原始二进制文件; 获取hex, 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); 

Java:谷歌search在Sun的论坛上find这个链接

具体(我没有尝试过这个我自己)

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

我这样做了:

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

那么Float和Double类(在Java中)都有一个toHexString('float')方法,所以在hex转换

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

易如反掌!

我不得不考虑在这里张贴一段时间,因为这可能会激发同行编程人员与C做坏事。我决定发布它,但只要记住:不要写这种代码,没有适当的文件,甚至没有这样的严重的应用程序想三次。

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

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

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

不幸的是,我们不能直接使用这个函数来打印我们的floatvariables,所以我们不得不进行一些修改。 对于所有读过卡马克的 Quake反转平方根技巧的人来说,黑客可能都很熟悉。 这个想法是为我们的浮点variables设置一个值,然后为我们的长整型variables获取相同的位掩码。 所以我们把f的内存地址转换成一个long *值,然后用这个指针来得到f的位掩码作为一个长符号。 如果将这个值打印为无符号长整型,结果将是一团糟,但是这些位与原始浮点值相同,所以它并不重要。

 int main(void) { long unsigned lu; float f = -1.1f; lu = *(long*)&f; printbin(lu, 32); printf("\n"); return 0; } 

如果你认为这个语法太糟糕了,那你是对的。

在Haskell中,没有可以访问浮点的内部表示。 但是,你可以从许多格式中进行二进制连续化,包括Float和Double。 以下解决scheme对于具有Data.Binary实例的任何types都是通用的:

 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) 

但是,如果您需要以这种方式访问​​浮点值,那么您可能是在做错了什么。 真正的问题可能是如何访问浮点数的指数和有效数? 答案是Prelude的指数和重要性:

 significand 3.14 0.785 exponent 3.14 2 

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' 

显然没有人关心提到hex指数符号是多么微不足道,所以这里是:

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

你可以很容易地使用C#中的这样的代码将floatvariables转换为intvariables(或者double变长)

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

在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长参数是一个无符号long,所以它可以浮动,你可以使用别的比bitset和扩展断言。

顺便说一句,Cletus的build议失败了,因为你需要一个“未知的long long”来覆盖double,无论如何你需要显示二进制(1或0)表示的东西。