精确度(你想知道的C语言 3.8)

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)
 
转载请注明出处

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值