彻底弄懂计算机如何存储小数和处理小数产生错误的原因

三、计算机处理小数时出现错误的原因

3.1用二进制表示小数

二进制:11.101 小数点后表示2的 - XX次方

十进制:10.52 小数点后表示10 的 -XX次方

3.2二进制永远无法表示十进制的0.1

如同十进制无法表示1/3一样,二进制表格如下:

二进制数十进制数
0.00000
0.00010.0625
0.00100.125

2的负多少次方,无论怎么累加都无法得到0.1

3.3什么是浮点数

定点数:321.123 小数点是固定的;

浮点数:0.123x10-8 小数点不是固定的,按照后面的来确定小数点的位置

浮点数的组成:对于计算机来说,基数是确定的,为2,所以只用三个参数来表示浮点数:符号,尾数,指数

请添加图片描述

双精度与单精度浮点数的构成:

双精度:

请添加图片描述

单精度:

请添加图片描述

3.4正则表达式和excess系统

这里的正则表达式:指的是只能用一种特定形式去表示小数,如十进制的科学计数法所规定的一样,二进制也有特定的规则

浮点数的正则表达式:将小数点前面的值固定为1的规则,让后将1去掉,完成正则,得到尾数部分

请添加图片描述

指数部分该如何确定:EXCES

如单精度的指数部分有8位,最大能表示的为1111 1111 (十进制的255),取它的1/2 ,即0111 1111 =127(小数部分舍弃)表示0;

举个例子:1~10有十个数字,如果取中间的5作为0, 那么10就表示:10-5 = +5 ,1就代表:1 - 5 = -4 ;这就是所谓的EXCESS系统

请添加图片描述

在实际程序中看负数到底是怎么表示的:

#include<stdio.h>
#include<string.h> 

int main() {
	float data;
	unsigned long buff;
	int i;
	char s[34];
	
	// 将0.75以单精度的形式保存起来
	data = (float)0.75;
	
	// 将数据复制到4个字节长度的整数变量buff中,然后逐一提取每一位
    // memcpy(viod* des, void* src, unsigned int count)
    // 将src 指针所指的内容复制到dec所指向的位置, 大小为count个字节
	memcpy(&buff, &data, 4);
    // buff不管0.75的二进制格式(符号位-指数位-尾数位),直接同一对待
    // 看这个0.75二进制码以十进制读出来
	printf("%lu\n",buff);
	
	// 逐一提取每一位
	for (i =33; i >=0; i-- ){
		if(i==1 || i == 10)
			// 在符号位,指数位与尾数位之间加入-分界符来使得表示更加清晰 
			s[i]= '-';
		else{
			// 将buff里的数转换为2进制
			if(buff % 2 == 1){
				s[i]='1';
			} else{
				s[i] = '0';
			}
			buff /=2; 
			
		} 
	} 
	s[34]='\0';
	
	printf("%s\n",s);
}

结果如下:

请添加图片描述

符号位:0 因为0.75是个正数

尾数部分1000…还原为小数点前为1的形式:1.10000…. = 1* 2的0次幂 + 1*2的-1次幂 = 1.5

指数部分 0111 1110 = 126 即126 - 127 = -1;

最终结果 = 尾数部分 x 指数部分 :1.5* 0.5(2的-1次方) = 0.75

3.5 如何避免出错

第一种策略:回避策略:允许一定程度的误差

第二种策略:涉及到金融时,先将小数转换为整数,因为整数计算一定不存在错误,将结果再转换成小数显示出来

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值