浮点逆二进制表示
Floating point inverse binary representation
我对以下代码感到困惑:
int main()
{
std::cout << std::bitset<32>(10.0f) << std::endl;
std::cout << std::bitset<32>(-10.0f) << std::endl;
float x = 10.0f;
std::bitset<32> bsx(x);
float y = -10.0f;
std::bitset<32> bsy(y);
std::cout << bsx << std::endl;
std::cout << bsy << std::endl;
}
第二个只是(是的,它只是一个被截断的第一个):
int main()
{
std::cout << std::bitset<32>(10.0f) << std::endl;
std::cout << std::bitset<32>(-10.0f) << std::endl;
}
我得到以下输出:
第一个:
00000000000000000000000000001010
00000000000000000000000000000000
00000000000000000000000000001010
11111111111111111111111111110110
第二个:
00000000000000000000000000001010
00000000000000010010000001101000
系统是 macOS Sierra (10.12.3) 上的 Clang 4.0.0,据我所知这里的浮点数是 32 位。
(用 g++ -pedantic -std=c++14
编译。)
我唯一知道的浮点数是 IEEE-754,它规定应该有一个单独的符号位。第一个程序的最后输出似乎使用了补码...
而其他的完全令人困惑..所有零和有点随机的输出,即使使用相同的代码,也只是被截断了..
我误会了什么?我在代码中的某处出现未定义的行为吗?不懂语法?或者由于某种原因浮点数不能表示为位集?
此代码不显示浮点数的二进制表示,不。因为没有std::bitset
constructors取浮点数。
它是这样工作的:
#include <bitset>
#include <iostream>
inline unsigned U(float f) { return (unsigned&) f; }
int main()
{
std::cout << std::bitset<32>(U(10.0f)) << std::endl;
std::cout << std::bitset<32>(U(-10.0f)) << std::endl;
return 0;
}
我添加了另一种格式的显式重新读取值。
输出是
01000001001000000000000000000000
11000001001000000000000000000000
(当然,对于平台特定细节的传统免责声明应放在此处。)
更新:内存别名存在问题,导致转换器可以按以下方式更好地编写(至少对于现代 GCC 和 Clang):
inline unsigned U(float f) {
unsigned R;
memcpy(&R, &f, sizeof(R));
return R;
}
现代编译器将此 memcpy() 视为 "bitcast" 运算符,并在内部将其转换为一种适当的寄存器移动。否则,您可能会遇到一些奇怪的别名问题。
但是,这种方法对于 ICC 来说仍然更糟,它更喜欢不同类型成员的联合:
inline unsigned U(float f) {
union {
unsigned u;
float f;
} t;
t.f = f;
return t.u;
}
对于不同的语言和版本,哪种类型的 bitcasting 更好,众说纷纭,在此不一一赘述。
我对以下代码感到困惑:
int main()
{
std::cout << std::bitset<32>(10.0f) << std::endl;
std::cout << std::bitset<32>(-10.0f) << std::endl;
float x = 10.0f;
std::bitset<32> bsx(x);
float y = -10.0f;
std::bitset<32> bsy(y);
std::cout << bsx << std::endl;
std::cout << bsy << std::endl;
}
第二个只是(是的,它只是一个被截断的第一个):
int main()
{
std::cout << std::bitset<32>(10.0f) << std::endl;
std::cout << std::bitset<32>(-10.0f) << std::endl;
}
我得到以下输出: 第一个:
00000000000000000000000000001010
00000000000000000000000000000000
00000000000000000000000000001010
11111111111111111111111111110110
第二个:
00000000000000000000000000001010
00000000000000010010000001101000
系统是 macOS Sierra (10.12.3) 上的 Clang 4.0.0,据我所知这里的浮点数是 32 位。
(用 g++ -pedantic -std=c++14
编译。)
我唯一知道的浮点数是 IEEE-754,它规定应该有一个单独的符号位。第一个程序的最后输出似乎使用了补码...
而其他的完全令人困惑..所有零和有点随机的输出,即使使用相同的代码,也只是被截断了..
我误会了什么?我在代码中的某处出现未定义的行为吗?不懂语法?或者由于某种原因浮点数不能表示为位集?
此代码不显示浮点数的二进制表示,不。因为没有std::bitset
constructors取浮点数。
它是这样工作的:
#include <bitset>
#include <iostream>
inline unsigned U(float f) { return (unsigned&) f; }
int main()
{
std::cout << std::bitset<32>(U(10.0f)) << std::endl;
std::cout << std::bitset<32>(U(-10.0f)) << std::endl;
return 0;
}
我添加了另一种格式的显式重新读取值。 输出是
01000001001000000000000000000000
11000001001000000000000000000000
(当然,对于平台特定细节的传统免责声明应放在此处。)
更新:内存别名存在问题,导致转换器可以按以下方式更好地编写(至少对于现代 GCC 和 Clang):
inline unsigned U(float f) {
unsigned R;
memcpy(&R, &f, sizeof(R));
return R;
}
现代编译器将此 memcpy() 视为 "bitcast" 运算符,并在内部将其转换为一种适当的寄存器移动。否则,您可能会遇到一些奇怪的别名问题。 但是,这种方法对于 ICC 来说仍然更糟,它更喜欢不同类型成员的联合:
inline unsigned U(float f) {
union {
unsigned u;
float f;
} t;
t.f = f;
return t.u;
}
对于不同的语言和版本,哪种类型的 bitcasting 更好,众说纷纭,在此不一一赘述。