Q: 只要涉及到浮点数,每本书基本都会说它不是精确的,我们该如何理解精确二字?
A: 精确永远都是相对而言。当我们认为1、2、3...自然数是精确的,自然C语言中int/char都是精确的。如果我们认为1.33是精确的,那么它就是精确的。那为什么浮点数会被认为不是精确的呢?
以4字节浮点数为例,符号位/指数位和有效位的位数都是固定的,当某个浮点数的有效位超出预设,那么就不能精确表达了。
对于int来说,其实也不能说是精确的,当我们认为间隔1其实不是精确,那int 1和2至少一个是不精确的!
Q:浮点数1.0是精确的吗?
A: 当然是精确的。先写一份可以dump 浮点数内部二进制数据的程序:
/*
Xi Chen(511272827@qq.com)
cxsjabcabc
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void dump_bits(void *p, int bytes)
{
int i, j;
int bits_stack[32] = {0};
int *bits;
char *pc;
int bits_len;
bits = bits_stack;
bits_len = 32;
if (bytes > 4) {
bits = (int *)malloc(bytes * 8);
if (!bits)
return;
bits_len = bytes * 8;
memset(bits, 0, bits_len);
}
pc = (char *)p;
for (i = bytes - 1; i >= 0; --i) {
unsigned char c = *(unsigned char *)(pc + i);
j = bits_len - 1 - i * 8;
while(c) {
bits[j--] = c % 2;
c /= 2;
}
}
for (i = 0; i < bits_len; ++i) {
printf("%d ", bits[i]);
if ((i + 1) % 4 == 0)
printf(" ");
}
printf("\n");
if (bytes > 4)
free(bits);
}
int main(int argc, char *argv[])
{
float f;
scanf("%f", &f);
dump_bits(&f, sizeof(f));
return 0;
}
1.0:
0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
(MSB --> LSB)
b'31 符号位: 正数为0.
b'[30:23] 指数位(127+真实的指数): 1.0E0 --> 最终为127,即0111 1111.
b'[22:0] 小数位: 默认省略左侧的1, 1.XXXXXX 红色部分为实际数据。如上,即为0.
可以看到,1.0是很精确的存储的,因为小数位没有近似,而是准确值。
Q: 1.33是精确的吗?
A:
0 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 1
按照1.0的分析,差别在小数位,如下小数点之后的数值。
1.0 1 0 1 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 1
我们编写代码计算上面的小数位计算得到多少。
/*
Xi Chen(511272827@qq.com)
cxsjabcabc
*/
#include <stdio.h>
#include <string.h>
int pow_int(int base, int n)
{
int ret;
ret = 1;
while(n > 0) {
ret *= base;
--n;
}
return ret;
}
void cal_bits(char *s)
{
int len;
int i;
int sum = 0;
len = strlen(s);
for(i = 0; i < len; ++i) {
sum += pow_int(2, len - 1 - i) * (s[i] - '0');
}
printf("%d/%d\n", sum, 2 << (len - 1));
}
int main(int argc, char *argv[])
{
char bits[32] = {0};
scanf("%s", bits);
cal_bits(bits);
return 0;
}
输入: 01010100011110101110001 (1.33的小数部分)
2768241/8388608 = 0.33000004291534424
可以看到,1.33的实际表示并不是精确的1.33.
作者: 陈曦
环境: MacOS 10.14.5 (Intel i5)
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Linux 3.16.83 (Ubuntu)
转载请注明出处