使用 int 指针的 float 位表示
Posted
技术标签:
【中文标题】使用 int 指针的 float 位表示【英文标题】:Bit representation of float using an int pointer 【发布时间】:2018-09-30 14:08:51 【问题描述】:我有以下练习:
实现一个函数 void float to bits(float x) 打印位 x 的表示。提示:将浮点数转换为 int 会截断 小数部分,但没有信息丢失,将浮点指针转换为 一个 int 指针。
现在,我知道浮点数由符号位表示,一些位表示尾数,一些位表示基数,一些位表示指数。这取决于我的系统使用了多少位。
我们这里面临的问题是我们的号码基本上有两个部分。让我们考虑8.7
这个数字的位表示(据我所知)如下:1000.0111
现在,浮点数以前导零存储,因此 8.8
将变为 0.88*10^1
所以我必须以某种方式从我的记忆中取出所有信息。我真的不明白我应该怎么做。那应该提示我什么?整数指针和浮点指针有什么区别?
目前我有这个:
void float_to_bits()
float a = 4.2345678f;
int* b;
b = (int*)(&a);
*b = a;
std::cout << *(b) << "\n";
但我真的不明白这里暗示背后的大局。如何获得尾数、指数、符号和基?我还尝试使用按位运算符>>、
【问题讨论】:
你的理解是错误的。 8.7 不会存储为“1000.0111”。您的第一步是实际研究浮点值在您的平台上是如何表示的。在您真正知道它们是如何存储的之前,尝试编写任何代码都是浪费时间,因为您不知道应该期待什么。当然,首先盲目地转储构成float
的原始字节是很有意义的,然后看看您是否可以自己破译它,和/或验证您的研究发现的信息。
是的,很久以前我就这样做了。会很快刷新它。但它很熟悉,但我仍然有同样的问题。我完全不明白这个提示。我怎么会得到例如尾数?
给定一个字节,你如何得到它的最低位?获取尾数涉及相同的方法。
你能详细说明这个问题吗?字节是如何给出的?在纸上?在 c++ 中,如果是这样,如何?在 c++ 中,我会使用 > 和 & 但这不是重点。我可以例如还可以获得整数的按位表示 - 但我看不到如何从我的浮点数中获取实际的信息字节。我的问题是“获取”数据而不是处理数据。
打开你的 C++ 书到解释强制转换的章节,它应该有很多例子说明如何将指向一种类型的指针转换为指向不同类型的指针。因此,您只需获取一个指向浮点数的指针并将其转换为指向unsigned char
的指针。你知道sizeof(float)
是什么,所以这就是你可以通过转换后的指针访问多少个unsigned char
s,到那时你就完成了。
【参考方案1】:
您的老师给出的提示具有误导性:在不同类型之间转换指针至多是实现定义的。但是,如果定义了unsigned char
,则memcpy(...)
将对象添加到大小合适的数组中。然后可以将结果数组的内容分解为位。这是使用十六进制值表示位的快速技巧:
#include <iostream>
#include <iomanip>
#include <cstring>
int main()
float f = 8.7;
unsigned char bytes[sizeof(float)];
std::memcpy(bytes, &f, sizeof(float));
std::cout << std::hex << std::setfill(‘0’);
for (int b: bytes)
std::cout << std::setw(2) << b;
std::cout << ‘\n’;
请注意,IEEE 754 二进制浮点 不 存储完整的有效位(标准不使用 尾数 作为术语),但非规范化值除外:32 位花车商店
1 位用于符号 8 位的指数 23 位用于归一化有效位,其中隐含非零高位【讨论】:
谢谢,我要研究一下,但我认为我不应该使用字符和/或数组。 是的。但是,您的老师的建议会导致未定义的行为:尝试通过指针读取值或对不同类型的引用违反了严格的别名规则。memcpy()
的使用是“神奇的”,因为编译器需要识别它并公开字节,即使它通常会违反别名规则。
C++ 标准不保证字节的值是什么,也就是说,对内置类型的表示没有任何限制。但是,它确实保证 memcpy()
到一个字节数组并返回将保留原始值(没有别名问题)。因此,字节将旧的东西将代表原始值的位。 reinterpret_cast<...>(...)
ing 指针没有 mych 定义的行为,但有很多陷阱会导致未定义的行为,通常充其量是实现定义的行为。
这个答案及其作者的 cmets 错误地陈述了 C++ 规则。读取指向差异类型的指针并不总是违反别名规则。 C++ 2017 (draft n4659) 6.10 [basic.lval] 8 特别允许读取char
、unsigned char
和std::byte
类型,以及其他一些情况。而不是“魔法”,是使memcpy
成为正确方法的原因,以及它的语义继承自 C 的事实,它指定它复制字符。 C++ 还为指针转换指定了一些语义;它们不是完全由实现定义的。【参考方案2】:
提示将指导您如何将 Float 传递到 Integer 而无需通过值转换。
当您将浮点值分配给整数时,处理器会删除小数部分。 int i = (int) 4.502f;
将导致 i=4;
但是当你将一个 int 指针 (int*
) 指向一个浮点的位置时,
没有进行转换,当您读取 int*
值时也是如此。
为了显示表示,我喜欢看到 HEX 数字, 这就是为什么我的第一个例子是用 HEX 给出的 (每个十六进制数字代表4个二进制数字)。
但也可以打印为二进制, 而且有很多方法(我最喜欢这个!)
遵循带注释的示例代码: 也可@Culio
#include <iostream>
#include <bitset>
using namespace std;
int main()
float a = 4.2345678f; // allocate space for a float. Call it 'a' and put the floating point value of `4.2345678f` in it.
unsigned int* b; // allocate a space for a pointer (address), call the space b, (hint to compiler, this will point to integer number)
b = (unsigned int*)(&a); // GREAT, exactly what you needed! take the float 'a', get it's address '&'.
// by default, it is an address pointing at float (float*) , so you correctly cast it to (int*).
// Bottom line: Set 'b' to the address of a, but treat this address of an int!
// The Hint implied that this wont cause type conversion:
// int someInt = a; // would cause `someInt = 4` same is your line below:
// *b = a; // <<<< this was your error.
// 1st thing, it aint required, as 'b' already pointing to `a` address, hence has it's value.
// 2nd by this, you set the value pointed by `b` to 'a' (including conversion to int = 4);
// the value in 'a' actually changes too by this instruction.
cout << a << " in binary " << bitset<32>(*b) << endl;
cout << "Sign " << bitset<1>(*b >> 31) << endl; // 1 bit (31)
cout << "Exp " << bitset<8>(*b >> 23) << endl; // 8 bits (23-30)
cout << "Mantisa " << bitset<23>(*b) << endl; // 23 bits (0-22)
【讨论】:
嗯,我认为这不是他们想要的。我真的认为我应该做一些明智的操作,直接从内存中读取数据。不过我只是猜测,谢谢。要调查一下。还有,什么是十六进制? @xotix Hex 是“十六进制”,这是一种编写二进制文件的简写方式,可以减少 75% 的文本。检查维基。 @doug 是的,我对 hex 很熟悉,没有关于 hex 的问题。我的意思是他之前使用的变量 hex,我在代码中的任何地方都找不到它。想也许它是一面旗帜,但它看起来不像。无论如何,他无论如何都更新了答案。 :) hex 实际上是在 stdlib std::hex 中定义的格式化程序......认为它是一个变量是误导性的。见cplusplus.com/reference/ios/hex FWIW,仅对于标准化数字,我猜浮点数的 23 位尾数(有效位是首选术语)应该与 0x800000 进行或运算以添加隐藏位。并且指数也应该是无偏的(IIRC 减去 127)。以上是关于使用 int 指针的 float 位表示的主要内容,如果未能解决你的问题,请参考以下文章