带符号的浮点变量转换为无符号DWORD [英] Signed Floating Point Variable Conversion to unsigned DWORD

查看:212
本文介绍了带符号的浮点变量转换为无符号DWORD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将一个有符号的浮点变量转换为DWORD ... DWORD被另一个程序使用,所以DWORD变量类型是重要的...



首先...一个签名的DWORD可以解释为一个无符号的DWORD ..?



也...如何将一个有符号的浮点转换为DWORD ..?

解决方案


我试图将签名的浮点变量转换为DWORD ... DWORD被另一个程序使用,因此DWORD变量类型很重要...



首先...可以将带符号的DWORD解释为无符号DWORD。 ?



也...如何将一个签名的浮点数转换为DWORD(signed)..?


DWORD 是由Windows API定义的32位无符号整数类型。没有这样的东西,如签名的DWORD。



在C ++中,所有浮点型类型( float double long double )是有符号类型,因此谈论一个签名的浮点数。假设您的意思是它可以是一个负值。将负浮点值转换为无符号整数的主要可能性有两种:




  • >将浮点值,例如 -1.23 转换为有符号整数,然后以2的适当倍数进行调整 将其带入无符号整数范围,或

  • 如同浮点值,再次说 -1.23 ,以2的适当倍数调整 n ,使其进入无符号整数范围,然后转换为无符号整数类型。




这些过程通常会产生不同的结果,差别为1.但是,测试它,这是Visual C ++使用的第一个过程11.0和MinGW g ++ 4.7.1。我怀疑这是由标准强制的(例如,C ++ 11最终得到关于负数的整数除法的结果的明确规则):

  #include< math.h> 
#include< windows.h>
using namespace std;

#include< iostream>
DWORD test1()
{
double floatValue = -1.23456;
DWORD const dwValue = floatValue;

cout<< dwValue<< endl;
return dwValue;
}

DWORD test2()
{
double floatValue = -1.23456;
double reduced = floatValue +(1uLL << 32);
DWORD const dwValue = reduced;

cout<< dwValue<< endl;
return dwValue;
}

int main()
{
cout<< DWORD(-1)<< endl;
DWORD const t1 = test1(); cout < 1uLL + DWORD(-1)-t1 < endl;
DWORD const t2 = test2(); cout < 1uLL + DWORD(-1)-t2 < endl;
}

使用Visual C ++ 11.0和MinGW g ++输出4.7.1:

 
4294967295
4294967295
1
4294967294
2

通常,转换(通过简单赋值或初始化)会丢失数据。



编译器可能会警告。一个可能的方法使它关闭,这可能或可能不工作,然后使用 static_cast 使转换明确。无论如何,请注意,在一般情况下,转换必须丢失数据,因为一般来说,浮点值的位数多于 DWORD 。 / p>

但是,有一种情况是 DWORD 有足够的位,



因此,您可以表示任何 float / code>值作为 DWORD 值与相同的位,但数值之间的连接看起来很随意。它是否将实际有用取决于您的其他应用程序。它预期什么,或它可以处理什么?

  #include< windows.h> 
#include< iostream>
using namespace std;

DWORD dwordBitsFrom(float const number)
{
return * reinterpret_cast< DWORD const *>(& number);
}

float floatFromBits(DWORD const bits)
{
return * reinterpret_cast< float const *>(& bits);
}

int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom(original);
float const reconstituted = floatFromBits(bits);

cout<<原始< endl;
cout<<位<< endl;
cout<<重构 endl;
}



输出,使用Visual C ++ 11和g ++ 4.7.1有用的Windows C ++编译器):

 
-1.23
3214766244
-1.23

但是,请注意,虽然后面的转换在Windows 中定义得很好,但Windows规则不受C ++标准的支持。从严格的形式上看,不适当地将上述代码视为与平台无关的,上述打破了C ++的严格别名限制规则。其中g ++非常乐意通知您:

 
[D:\dev\test]
> gnuc - strict-aliasing foo.cpp
foo.cpp:在函数'DWORD dwordBitsFrom(float)':
foo.cpp:7:55:warning:dereferencing类型冲突的指针将会破坏严格别名规则[ -Wstrict-aliasing]
foo.cpp:在函数'float floatFromBits(DWORD)':
foo.cpp:12:53:warning:dereferencing类型冲突的指针将会破坏严格别名规则[ Wstrict别名]

[D:\dev\test]
> _

为了使傻的编译器,如g ++快乐,你必须通过字节缓冲区进行转换。这是非常讨厌,因为警告是所有关于编译器检测你已经表达了你想要的,是不兼容的一些非常不可取的边缘优化,它可能适用。当它可以检测到它不应该,为什么不能不这样做不好的事情,而不是警告它无能为力呢?或者,为什么不能只是不做它呢?因为没有人想要它。



但是无论如何,这里的代码使g ++关闭:

 code> #include< windows.h> 
#include< iostream>
#include< string.h> // memcpy
using namespace std;

static_assert(sizeof(DWORD)== sizeof(float),y DWORD没有相同大小的浮点数?

int const nBytes = sizeof(DWORD);

DWORD dwordBitsFrom(float const number)
{
char buffer [nBytes];
DWORD结果;

memcpy(buffer,& number,nBytes);
memcpy(& result,buffer,nBytes);
return result;
}

float floatFromBits(DWORD const bits)
{
char buffer [nBytes];
float result;

memcpy(buffer,& bits,nBytes);
memcpy(& result,buffer,nByte);
return result;
}

int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom(original);
float const reconstituted = floatFromBits(bits);

cout<<原始< endl;
cout<<位<< endl;
cout<<重构 endl;
}

当然,因为它更冗长和效率更低的代码,关闭一个愚蠢的编译器(即g ++)是不值得的。就个人而言,我认为这不值得。 而只需对g ++说 -fno-strict-aliasing ,并使用 reinterpret_cast ,因为这是 > ,为什么我们使用该语言。



总结一下,如果你的其他程序需要一个可能是接近原始浮点值,然后通过分配或初始化转换为 DWORD ,可能使用 static_cast

如果您的其他程序需要 float 位 >值,那么只需使用 reinterpret_cast 转换即可。上面的代码显示了如何使用更低效,详细和错误吸引的 memcpy ,而只是为了满足g ++编译器。但是我的建议是,如果这是相关的,那么只是通过 -fno-strict-aliasing (另一个有用的这样的选项使g ++编译器符合实用性,是 -fwrapv ,应始终使用IMHO)。


I am trying to convert a signed floating point variable to DWORD...the DWORD is to be used by another program so the DWORD variable type is important...

firstly...can a signed DWORD be interpreted as an unsigned DWORD..?

also...how can i convert a signed float to DWORD(signed)..?

解决方案

I am trying to convert a signed floating point variable to DWORD...the DWORD is to be used by another program so the DWORD variable type is important...

firstly...can a signed DWORD be interpreted as an unsigned DWORD..?

also...how can i convert a signed float to DWORD(signed)..?

DWORD is a 32-bit unsigned integer type defined by the Windows API. There is no such thing as a “signed DWORD”. Possibly you mean a corresponding signed type.

In C++ all floating point types (float, double and long double) are signed types, so it’s unusual to talk about a “signed floating point”. Presumably you mean that it can be a negative value. And there are two main possibilities for converting a negative floating point values to unsigned integer:

  • as if the floating point value, say -1.23, is converted to signed integer, and then adjusted by a suitable multiple of 2n to bring it into the unsigned integer range, or

  • as if the floating point value, again say -1.23, is adjusted by a suitable multiple of 2n to bring it into the unsigned integer range, and then converted to the unsigned integer type.

These procedures will generally yield different results, differing by 1. However, testing it, it's the first procedure that's used by Visual C++ 11.0 and MinGW g++ 4.7.1. And I suspect that somehow this is mandated by the standard (e.g., C++11 finally got clear rules about the result of integer division of negative numbers):

#include <math.h>
#include <windows.h>
using namespace std;

#include <iostream>
DWORD test1()
{
    double floatValue = -1.23456;
    DWORD const dwValue = floatValue;

    cout << dwValue << endl;
    return dwValue;
}

DWORD test2()
{
    double floatValue = -1.23456;
    double reduced    = floatValue + (1uLL << 32);
    DWORD const dwValue = reduced;

    cout << dwValue << endl;
    return dwValue;
}

int main()
{
    cout << DWORD(-1) << endl;
    DWORD const t1 = test1();  cout << 1uLL + DWORD(-1) - t1 << endl;
    DWORD const t2 = test2();  cout << 1uLL + DWORD(-1) - t2 << endl;
}

Output, with Visual C++ 11.0 and MinGW g++ 4.7.1:

4294967295
4294967295
1
4294967294
2

Generally, the conversion (performed by simple assignment or initialization) loses data.

The compiler may warn about that. One possible way to make it shut up, which may or may not work, is then to use a static_cast to make the conversion explicit. Anyway, be aware that the conversion must lose data in the general case, because in general a floating point value has more bits than a DWORD.

There is one case, however, where a DWORD has enough bits, and that's for a value of type float, which in Windows is 32-bit IEEE.

You can therefore represent any float value as a DWORD value with the same bits, but the connection between numerical values will then seem pretty arbitrary. And whether it will be practically useful depends on your other application. What does it expect, or what can it handle?

#include <windows.h>
#include <iostream>
using namespace std;

DWORD dwordBitsFrom( float const number )
{
    return *reinterpret_cast< DWORD const* >( &number );
}

float floatFromBits( DWORD const bits )
{
    return *reinterpret_cast< float const* >( &bits );
}

int main()
{
    float const original        = -1.23;
    DWORD const bits            = dwordBitsFrom( original );
    float const reconstituted   = floatFromBits( bits );

    cout << original << endl;
    cout << bits << endl;
    cout << reconstituted << endl;
}

Output, with Visual C++ 11 and g++ 4.7.1 (and indeed any practically useful Windows C++ compiler):

-1.23
3214766244
-1.23

Note, however, that while this latter conversion is well defined in Windows, the Windows rule is not supported by the C++ standard. From a strictly formal point of view, inappropriately regarding the above code as platform-independent, the above breaks the strict aliasing rules of C++. Which g++ is very happy to inform you about:

[D:\dev\test]
> gnuc --strict-aliasing foo.cpp
foo.cpp: In function 'DWORD dwordBitsFrom(float)':
foo.cpp:7:55: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
foo.cpp: In function 'float floatFromBits(DWORD)':
foo.cpp:12:53: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

[D:\dev\test]
> _

In order to make silly compilers such as g++ happy, you have to do the conversion via a buffer of bytes. It's pretty annoying, because the warning is all about the compiler detecting that what you have expressed that you want, is not compatible with some very undesirable marginal optimizations that it might apply. And when it can detect that it shouldn't, why can't it just not not do that undesirable thing, instead of warning about its inability to do it? Or, why can't it just not not do it at all? Since nobody wants it.

But anyway, here's code to make g++ shut up:

#include <windows.h>
#include <iostream>
#include <string.h>         // memcpy
using namespace std;

static_assert( sizeof( DWORD ) == sizeof( float ), "y DWORD no same size float?" );

int const nBytes = sizeof( DWORD );

DWORD dwordBitsFrom( float const number )
{
    char    buffer[nBytes];
    DWORD   result;

    memcpy( buffer, &number, nBytes );
    memcpy( &result, buffer, nBytes );
    return result;
}

float floatFromBits( DWORD const bits )
{
    char    buffer[nBytes];
    float   result;

    memcpy( buffer, &bits, nBytes );
    memcpy( &result, buffer, nBytes );
    return result;
}

int main()
{
    float const original        = -1.23;
    DWORD const bits            = dwordBitsFrom( original );
    float const reconstituted   = floatFromBits( bits );

    cout << original << endl;
    cout << bits << endl;
    cout << reconstituted << endl;
}

Of course, since it's much more verbose and less efficient code, one may decide that shutting up a silly compiler (namely g++) is not worth it. Personally, I think it's not worth it. Instead, just say -fno-strict-aliasing to g++, and use the reinterpret_cast, because that's what it's for, why we have it in the language.

Summing up, if your other program expects a numerical value that if possible is close to the original floating point value, then just convert to DWORD by assigning or initializing, possibly using a static_cast to suppress compiler warnings.

And if your other program expects the bits of a float value, then just use the reinterpret_cast conversion. The code above shows how to use the more inefficient, verbose and bug-attracting memcpy instead just to please the g++ compiler. But my advice is, if that's relevant, then just suppress the g++ warning via -fno-strict-aliasing (another useful such option to bring the g++ compiler into line with practicality, is -fwrapv, which IMHO should always be used).

这篇关于带符号的浮点变量转换为无符号DWORD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆