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;
}
}