C语言每日一题——第九天

第九天

在一开始的学习中,小明就头疼于计算机浮点数运算的误差。他决定看看浮点数的二进制是什么样的——尽管这么做对解决误差问题毫无帮助。

输入

程序执行时,通过scanf输入一个小数。

输出

打印这个小数对应的float变量的二进制。

示例

1

Input a float:0.123

0.123000
00111101111110111110011101101101

2

Input a float:2.03

2.030000
01000000000000011110101110000101

3

Input a float:-2.03

-2.030000
11000000000000011110101110000101

关键

指针的理解与运用,位运算和掩码

相关链接

浮点数的内部实现:C语言浮点数存储方式


解析

思考题:优化递归函数show_bin,使用循环替代递归。

#include <stdio.h>
#include <stdint.h>

void show_bin(const uint8_t *, size_t);

int main() {
    float value = 1;

    printf("Input a float: ");
    scanf("%f", &value);

    printf("\n%f\n",value);  // 为了美化输出,特意空出一行
    show_bin((uint8_t *) &value, sizeof(value));

    return 0;
}

/**
 * @brief       打印指针所示对象的二进制内容
 * @param ptr : 数据指针
 * @param size: 数据的长度
 */
void show_bin(const uint8_t *ptr, size_t size) {
    uint8_t key = 0b10000000;  // 掩码,用作按位与,0b是二进制标志

    // 由于指针指向数据对象的尾部,当数据长度大于1时,ptr指向的并不是数据的头部,因此要偏移ptr
    if (size > 1) {
        show_bin(ptr + 1, size - 1);
    }
    // 执行到这里说明 无需打印更“前面”的数据 或者 “前面”的数据已经打印完毕
    for (int i = 7; i >= 0; i--) {  // uint8 的长度是 8 位,所以循环8次; 
        // 注意这里 i 是从7往下减小

        // ((*ptr) & key) >> i 拆开讲
        // 首先是 (*ptr) 表示获取 ptr 指向位置的值。
        //由于 ptr 在前面被转换为 uint8_t* 类型,因此这个位置的值会被编译器视为长度为8位的正整数
        // 其次是 x & key , `&` 是“按位与”运算,
        // 如 101 & 001 = 001 (二进制表示,后同), 101 & 010 = 000, 101 & 100 = 100
        // 我们发现, 任意一个数与 (x个零)1(y个零) 做“按位与”运算,
        // 得到的均是 (x个零)(二进制下这个数第y+1位的值)(y个零)
        // 最后一步将这个数右移 y 位,得到的是 (x+y个零)(二进制下这个数第y+1位的值) 且这个数非1即0
        printf("%d", ((*ptr) & key) >> i);
        key >>= 1;
    }
}
posted @ 2022-10-05 22:52  风吹云动  阅读(129)  评论(0编辑  收藏  举报