


全文预览已结束
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C#浮点数精度丢失问题 C#中的浮点数,分单精度(float)和双精度(double):float 是 System.Single 的别名,介于-3.402823e38 和 +3.402823e38 之间的32位数字,符合二进制浮点算法的 IEC 60559:1989 (IEEE 754) 标准;double 是 System.Double 的别名,介于-1.79769313486232e308 和 +1.79769313486232e308之间的64位数字,符合二进制浮点算法的 IEC 60559:1989 (IEEE 754) 标准;我们知道,计算机只认识 0 和 1,所以数值都是以二进制的方式储存在内存中的。(对于人脑和计算机哪个聪明,个人更倾向于选择人脑,计算机只是计算得快,而且不厌其烦而已!)所以要知道数值在内存中是如何储存的,需先将数值转为二进制(这里指在范围内的数值)。根据 IEEE 754 标准,任意一个二进制浮点数 V 均可表示为:V = (-1 s) * M * (2 e)。其中 s 0, 1;M 1, 2);e 表示偏移指数。以 198903.19(10) 为例,先转成二进制的数值为:110000100011110111.0011000010100011(2)(截取 16 位小数),采用科学记数法等于1.100001000111101110011000010100011 * (2 17)(整数位是 1),即 198903.19(10) =(-1 0) *1.100001000111101110011000010100011 * (2 17)。整数部分可采用 除2取余法,小数部分可采用 乘2取整法。从结果可以看出,小数部分 0.19 转为二进制后,小数位数超过 16 位(我已经手算到小数点后 32 位都还没算完,其实这个位数是无穷尽的)。由于无法得到完全正确的数值,这里就引申出浮点数精度丢失的问题:/* 程序段1 */float num_a = 198903.19f;float num_b = num_a / 2;Console.WriteLine(num_a);Console.WriteLine(num_b);这段程序代码,我们预想中正确的结果应该是:198903.19 和 99451.595。但结果居然是!原因下面将讲到 .这里介绍另一种转小数部分的方法,有兴趣可以看下:假如结果要求精确到 N 位小数,那么只需要将小数部分乘以 2 的 N 次方(例如 N = 16,0.19 * (2 16),得到 12451.84)。取整数部分(12451),按整数的方法转为二进制,得到 11000010100011,不足 N 位在高位用 0 补足。结果 0.19 精确到 16 位后,用二进制表示为 0.0011000010100011。可以看出,若是小数部分乘以 2 的 N 次方后,可以得到一个整数,那么这个小数可以用二进制精确表示,否则则不可以。(原理很简单,根据二进制小数位转十进制的方法,反推回去就可以得到这个结果)在内存中,float 和 double 的储存格式是一致的,只是占用的空间大小不同。float 总共占用 32 位:从左往右,第 1 位是符号位,占 1 位;第 2-9 位是指数位,占 8 位;第 10-32 位是尾数位,占 23 位。double 总共占用 64 位,从左往右第 1 位也是符号位,占 1 位;第 2-12 位是指数位,占 11 位;第 13-64 位是尾数位,占 52 位。其中,符号位(即上文的 s,下同),0 代表正数,1 代表负数。对于 float,8位指数位的值范围为 0-255(10),由于指数(即上文的 e,下同)可正可负,而指数位的值是一个无符号整数。根据标准规定,储存时采用偏移值(偏移值为127)的方法,储存值为指数 + 127。例如 0111 0011(2) 表示指数 -12(10)((-12) +127= 115),1000 1011(2) 表示指数 12(10)(12+ 127 = 139)。另外,IEEE 754 规定(同样适用于 double):当指数全为 0 时,如果尾数全为 0,表示0(正负取决于符号位),如果尾数不全为 0,计算时指数等于 -126,尾数不加上第一位的1,而是还原为 0.xxxxxx 的小数,表示更接近 0 的小数;当指数全为 1 时,如果尾数全为 0,表示 无穷大(正负取决于符号位),如果尾数不全为 0,表示这不是一个数(NaN)。同样的,对于 double,11位指数位,储存时采用的偏移值为 1023。尾数位,由于所有数值均可以转换成 1.xxx * (2 N)(此处暂时忽略精度问题),所以尾数部分只保存小数部分(最高位的 1 不存入内存,提高 1 个位的精度)。以 float 198903.19 为例,二进制为1.100001000111101110011000010100011 * (2 17);数值为正数,符号位是 0;指数是 17,保存为 144(17 + 127= 144),即10010000(共 8 位,不足 8 位在高位用 0 补足);小数位是10000100011110111001100(截取 23 位);最终得到:01001000 01000010 00111101 11001100,按字节倒序顺序,转为十六进制就是:CC 3D 42 48float f_num = 198903.19f;var f_bytes = BitConverter.GetBytes(f_num);Console.WriteLine(float: 198903.19);Console.WriteLine(BitConverter.ToString(f_bytes);Console.WriteLine(string.Join( , f_bytes.Select(i = Convert.ToString(i, 2).PadLeft(8, 0);同样的格式,double198903.19 最终得到:01000001 00001000 01000111 10111001 10000101 00011110 10111000 01010010(最后两位结果为什么是 10 而不是 01,请参考浮点数的舍入),按字节倒序顺序,转为十六进制就是:52 B8 1E 85 B9 47 08 41double d_num = 198903.19d;var d_bytes = BitConverter.GetBytes(d_num);Console.WriteLine(double: 198903.19);Console.WriteLine(BitConverter.ToString(d_bytes);Console.WriteLine(string.Join( , d_bytes.Select(i = Convert.ToString(i, 2).PadLeft(8, 0);回到精度丢失的问题,由于小数位无法算尽,内存用截取精度的方式储存了转换后的二进制,这导致保存的结果并非是完全正确的数值。看回 程序段1 的例子,num_a 在内存中其实是保存为:01001000 01000010 00111101 11001100,换算成十进制就是:198903.1875;num_b 在内存中其实是保存为:01000111 11000010 00111101 11001100,换算成十进制就是:99451.59375;先看 num_b,由于 num_a 在内存中储存的值已经是不正确的,那么再利用其进行计算,得到的结果 99.9% 也会是不正确的。所以 num_b 的结果并不是我们想要的99451.595。然后为什么198903.1875 会变成198903.2,而99451.59375 会变成9
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 财务管理面试题及答案范例(高级)
- 保洁员人员面试题及答案
- 年职业病防治周试题及答案
- 2025年天津市南开区五马路小学小升初语文模拟试卷
- 安全感题库及答案解析
- 氟化工安全操作培训试题及答案解析
- 繁昌安全员证考试题库及答案解析
- 制球工三级安全教育(班组级)考核试卷及答案
- 江苏安全员b证是不是有题库及答案解析
- 外科麻醉护理学题库及答案解析
- 智能化设计资源管理-洞察及研究
- AI时代网络安全产业人才发展报告(2025年)-安恒信息
- 供电服务技巧培训
- 2025浙江大学医学院附属儿童医院膳食部劳务派遣后勤工人招聘(莫干山院区)备考模拟试题及答案解析
- 2024-2025学年广东省广州市花都区黄广中学八年级上学期10月考数学试卷(含答案)
- 2025-2026人教版(2024)七年级上册英语教学计划 (三篇)
- 绿色化学全套课件
- 自然辩证法复习重点讲义
- GB/T 31722-2025网络安全技术信息安全风险管理指导
- 电气自动化专业求职面试题目及答案
- 肝功能实验室指标解读
评论
0/150
提交评论