使用 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 chars,到那时你就完成了。 【参考方案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&lt;...&gt;(...)ing 指针没有 mych 定义的行为,但有很多陷阱会导致未定义的行为,通常充其量是实现定义的行为。 这个答案及其作者的 cmets 错误地陈述了 C++ 规则。读取指向差异类型的指针并不总是违反别名规则。 C++ 2017 (draft n4659) 6.10 [basic.lval] 8 特别允许读取charunsigned charstd::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 位表示的主要内容,如果未能解决你的问题,请参考以下文章

Float计算机表示形式

怎么把float型转换成int

C语言int和float有啥差别?

float型怎样强制转换成int型

如何使用Font Awesome字体图标

c语言中float型的精度问题