2009-12-06 122 views
3

我有一个无符号的长整数值,它代表使用IEEE-754格式的浮点数。在C++中以flo​​at方式打印出来最快的方法是什么?如何输出IEEE-754格式的整数作为浮点数

我知道一种方法,但我想知道是否有一个方便的C++实用程序会更好。的,我知道的方式

例子是:

union 
{ 
    unsigned long ul; 
    float f; 
} u; 

u.ul = 1084227584; // in HEX, this is 0x40A00000 

cout << "float value is: " << u.f << endl; 

(这会打印出“浮动值为:5”)

回答

6

您提出的联合方法是大多数人会采用的常用方法。然而,它在技术上在C/C++中用未定义的行为从联合中读取不同于最近编写的联合成员。尽管如此,它在几乎所有的编译器中都得到了很好的支持。

铸造指针,如Jon Skeet suggested,是一个坏主意 - 违反C.一个积极的优化编译器的strict aliasing规则将产生不正确的代码,这一点,因为它假定的类型unsigned long *float *永远互为别名指针。

最正确的方式,在符合标准的条款(即不调用不确定的行为),是通过char*投,因为严格别名规则允许char*指针引用任何其他类型的指针:

unsigned long ul = 0x40A00000; 
float f; 
char *pul = (char *)&ul; // ok, char* can alias any type 
char *pf = (char *)&f; // ok, char* can alias any type 
memcpy(pf, pul, sizeof(float)); 

虽然老实说,我只想用union方法去。从上面的cellperformance.com链接:

这是一个非常普遍的习惯用语,并得到所有主要编译器的支持。实际上,以任何顺序阅读和写给工会的任何成员都是可以接受的做法。

+0

哇,我没有意识到混叠会导致问题。感谢分享! – 2009-12-07 04:57:34

+0

用void *而不是char *可以接受吗? – 2009-12-07 04:58:19

+1

'float'不能保证表示为IEEE-754,所以使用任何形式的强制转换将具有IEEE754的字节数组转换为浮点数仍然未定义。 – 2013-04-04 03:38:12

3

编辑:我以前认为这“只是讨厌”,但它结果比我想象的更糟糕 - 请参阅评论以获取详细信息。我不推荐这种方法,但我要离开这里记录的可能性


您可以使用指针(和警告!):

long ul = 1084227584; 
float* fp = (float*) &ul; 
float f = *fp; 

(这可以被浓缩成一条线,但我认为它不会更清楚。)

基本上和你的工会一样......除非你确定所涉及的类型的大小,否则它们同样不可行。

如果您的平台支持它们,您应该使用整数和浮点类型的大小特定的类型名称。

+0

实际上,无论大小如何,它都依赖于实现。这比联合技巧好,这个技巧是未定义的,但仍然不好。 – 2009-12-06 20:27:00

+0

坏主意。这打破了C99严格的别名规则,并且一个积极的优化编译器可能会产生不正确的结果。请参阅http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html。 – 2009-12-06 20:43:09

+0

谢谢 - 我认为这很不愉快,但实际尺寸没有问题时实际上可能不会破碎。编辑更清楚,谢谢。请让我知道,如果你认为这是一个坏主意,答案应该完全删除 - 我很乐意承认。 – 2009-12-06 20:46:15

3

它只适用于sizeof(long)== sizeof(float)的32位机器或机器上。在现代机器上,你可能想用int来代替......而且如果你正在执行这个技巧,你真的必须小心。

3

我在想和Jon Skeet一样的东西,但是他打败了我。但是,我会比他做得更简洁一点。

cout << "float value is: " << *((float *) &ulValue)) << endl; 

你得到的一个指针unsigned long类型,然后重新解释,作为一个指针浮动,然后取消引用指针浮动产生的浮点值。

由于您在C++中这样做,使用reinterpret_cast而不是旧的C风格转换更清晰。

cout << "float value is: " << *(reinterpret_cast<float *>(&ulValue)) << endl; 
1

swegi有正确的方向,但错过了一个字符。正确的方法是

long l = 1084227584L 
float f = reinterpret_cast<float&>(l);