浮点型在内存中的存储分布方式因机器平台而异,完全理解所有机器平台中的浮点型存储无疑是一件相当麻烦的事。幸运的是,大多机器平台都遵守 IEEE-754 标准,很可能读者和我使用的平台正是使用的 IEEE-754 标准。

在C语言程序开发中,数值的处理是一门值得深究的科学。本文不可能将复杂的数值算法以及相关的C语言程序开发经验一一列出。事实上,讨论如何以理想的数值精度进行计算,就和讨论如何编写最快的C语言程序,如何设计一款优秀的软件一样,主要取决于程序员本身的综合素质。

鉴于此,这里将尝试介绍一些基础的,我认为每个C语言程序员都应该知道的内容。首先,我们应该明白C语言程序开发中的两个浮点数何时相等。可能读者并不觉得难,因为似乎C语言中的 == 运算符就能判断两个浮点数是否完全相等。然而实际上,C语言中的 == 运算符是逐位比较两个操作数的,而两个浮点数的精度总是有限的,在这种场景下,== 运算符的实际使用意义就没有那么大了。

读者应该已经明白,计算机存储浮点数时,很有可能是需要舍弃一些位的(如果该浮点数过长),如果 CPU 或者相应的程序没有按照预期四舍五入,那么使用 == 运算符判断两个浮点数是否相等可能会失败。例如,标准C语言函数库三角函数 cos() 的实现其实只是一种多项式近似,也就是说,我们并不能指望 cos(π/2) 结果的每一个位都为零。在C语言程序开发中,我们甚至不能准确的表示 π。

假设在某段C语言程序中有两个数字 1.25e-20 和 2.25e-20,它俩的差值是 1e-20,远小于 EPSILON,但是显然它俩并不相等。但是如果这两个数字是 1.2500000e-20和1.2500001e-20,那么就可以认为它们是相等的。也就是说,两个数字距离足够接近时,我们还需要关注需要匹配多少有效数字。

计算机存储空间总是有限的,因此数值溢出是C语言程序员最关心的问题之一。读者应该已经知道,如果向C语言中的最大无符号整数加一,该整数将归零,令人崩溃的是,我们并不能只通过看这个数字的方式获知是否有溢出发生,归零的整数看起来和标准零一模一样。当溢出发生时,实际上大多数 CPU 是会设置一个标志位的,如果读者懂得汇编,可以通过检查该标志位获知是否有溢出发生。

float 浮点数溢出时,我们可以方便的使用 +/- inf(无穷)。+inf(正无穷)大于任何数字,-inf(负无穷)小于任何数字,inf+1 等于 inf ,依此类推。因此在C语言程序开发中,一个小技巧是,将整数转换为浮点数,这样就方便判断后续处理是否会造成溢出了。处理完毕后,再将该数转换回整数即可。

不过,将整数转换为浮点数判断是否溢出也是要付出代价的,因为浮点数可能没有足够的精度来保存整个整数。32 位的整数可以表示任何 9 位十进制数,但是 32 位的浮点数最多只能表示 7 位的十进制数。所以,如果将一个很大的整数转换为浮点数,可能不会得到期望的结果。此外,在C语言程序开发中,int 与 float 之间的数值类型转换,包括 float 与 double 之间的数值类型转换,实际上是会带来一定的性能开销的。

读者应该明白,在C语言程序开发中,不管是否使用整数,都应该小心避免数值溢出的发生,不仅仅是最开始和最终结果数值可能溢出,在一些计算的中间过程,可能会产生一些更大的值。一个经典的例子是“C语言数字配方”计算复数的幅度问题,极可能造成数值溢出的C语言实现是下面这样的:

假设该复数的实部 re 和虚部 im 都等于 1e200,那么它们的幅度约为 1.414e200,这的确在双精度的允许范围内。但是,上述C语言代码的中间过程将产生 1e200 的平方值,也即 1e400,这超出了 inf 的范围,此时上面的实现函数计算的平方根将仍然是无穷大。

应该明白,上述C语言代码为了避免数值溢出,给出的实现实际上是一种近似。例如 im 等于 1e200,re 等于 1,那么 im/re 的平方仍然能够达到 1e400,这会造成数值溢出。但是平方 re/im 却是可以的,因为 1e-400 会被四舍五入到零,足够接近得到正确的答案。

幸运的是,就像上面求复数幅度避免出现数值溢出一样,避免两个接近的数字相减出现精度损失的方法也是有的,但是并没有一个通用的方法。这里给出一个简单的实例就是使用 1/x 的函数代替 x 的函数,这对于处理二次运算很有效。我的建议是,如果读者发现自己的C语言程序给出了令人怀疑的数值,就应该检查一下相应的减法运算了。

看到这里,相信读者应该想到C语言程序中的加法可能也有同样的问题:假设有数字 1.0,现在将其与 1e-20 相加。程序很可能认为 1e-20 很小,小于 EPSILON,于是忽略它,得到答案 1.0。这实际上也是一种精度损失。要完全规避C语言程序中的浮点数可能带来的问题,工作量无疑是巨大的。为了简化问题,我们通常认为浮点数带来的精度问题是这样的:对浮点数的操作越多,损失的精度也会越多。

正如前文举的例子 cos(π/2),C语言它的实现实际上是一种近似,得到的答案并不是 0,而是 6.12303E-17。不过就这个答案本身而言,它已经足够小,认为等于 0 也没什么大问题。但是如果我们下一步计算是除以 1e-17,那么得到的答案就约是 6 了,这与预期的零相差甚远。

最后,在C语言程序开发中,并不是只有浮点数才重要的,整数同样重要,它的精确性是一个有用的工具。有时程序需要跟踪变化的分数(例如比例因子)。在这种情况下,既然浮点数受各种因素影响,那么我们完全可以将该分数存储为整数分子和分母来避免问题。在需要使用浮点数时,随时再做一次除法运算就可以了。

计算机中答案没有小数怎么办,嵌入式编程中计算机是如何存储小数的相关推荐

  1. 窗体 局部变量转换为全局_从嵌入式编程中感悟「栈」为何方神圣?

    ID:技术让梦想更伟大 作者:李肖遥 何为变量? 变量一般可以细分为如下图: 本节重点为了让大家理解内存模型的"栈",暂时不考虑"静态变量" 的情况,并约定如下 ...

  2. 汇编在嵌入式编程中的作用_如何在嵌入式Power BI报表中以编程方式传递凭据

    汇编在嵌入式编程中的作用 In the article, How to embed a Power BI Report Server report into an ASP.Net web applic ...

  3. 嵌入式编程中volatile的重要性

    1.引言 volatile影响编译器编译的结果输出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码 ...

  4. 关于嵌入式编程中的uint8_t、uint16_t......

    在嵌入式编程中经常遇到用uint8_t.uint16_t.uint32_t.uint_fast16_t之类的关键字定义一些整型变量,但是具体表示什么意思,并不是太清楚,只是把它当成int之类的整型变量 ...

  5. 嵌入式编程中的堆栈溢出检测

    在嵌入式编程中,栈是一个很重要的概念,不管是裸机编程还是基于RTOS编程.函数形参.局部变量.函数调用现场的保护及返回地址.中断函数执行前线程保护及中断嵌套的现场的保护都依赖于栈空间.栈空间不足,程序 ...

  6. 嵌入式编程中的多任务与单任务,以及单任务的软件设计流程

    多任务与单任务 所谓"单任务系统"是指该系统不能支持多任务并发操作,宏观串行地执行一个任务.而多任务系统则可以宏观并行(微观上可能串行)地"同时"执行多个任务. ...

  7. union 的概念及在嵌入式编程中的应用

    union 概念 union 在中文的叫法中又被称为共用体,联合或者联合体,它定义的方式与 struct 是相同的,但是意义却与 struct 完全不同,下面是 union 的定义格式: union ...

  8. 学计算机和电脑办公的区别,自学编程和计算机科班出身的差别在哪?

    自学编程和科班出身的差别最大的在于学习的主体--人 但毫无例外的是,当两者之间相辅相成之时所能发挥的力量更大. 自学编程和计算机科班出身的差别在哪? 不同人的不同看法 看到一段好的产品,科班出身的会问 ...

  9. transactionscope 中的异步 处理 异常_PLC编程中的异常处理

    异常处理,是PLC编程中最重要,最核心的部分,也是一个机械设备,一套流水线是否有价值的体现.其实,异常处理,就好比是维生素,如果没有,并不影响设备的整体运行.但如果有,会使设备更加智能.那么,到底该怎 ...

  10. java中作用是什么_Java在编程中的作用是什么?

    2017-07-28 Java编程中更新XML文档的常 JAXP是Java API for XML Processing的英文字头缩写,中文含义是:用于XML文档处理的使用Java语言编写的编程接口. ...

最新文章

  1. 利用 Spring MVC 上传多文件到指定目录 spring upload files
  2. 从200多篇顶会论文看推荐系统前沿方向与最新进展
  3. Java 9:Process API的增强
  4. linux 关闭登录权限,linux – /var/www/html的权限[已关闭]
  5. leetcode - 983. 最低票价
  6. 网易有道词典2019年度十大热词:Vlog、PUA等上榜
  7. SQLite查询优化(转)
  8. WiFi 扫描处理过程
  9. 一种设想:打造小程序版本公号和自托管的公号,将你的网站/blog做到微信/微信公号里且与PC端合一
  10. Ubuntu安装Times NewRoman字体
  11. 《幸福人生 从心开始》讲座参后感
  12. 全球十大公司物联网战略,一个万物智能的世界即将到来
  13. Django 模型操作
  14. c语言什么是测试环境,vscode搭建与测试c语言运行环境
  15. 2019流量获取方式大盘点(实用技巧+PDF下载)
  16. 程序,批量启动程序脚本
  17. vmware 桥接不能联网问题
  18. 安裝 Installation of Torch7, Cuda, Cudnn, Nvidia Driver with GTX1070
  19. 一份网络专业毕业设计
  20. 2023年美赛论文写作方法——图表篇:美赛O奖中那些好看的图表是如何制作的?

热门文章

  1. python文件下载学习
  2. Atitit 安全登录退出管理法v3 tbb.docx 目录 1.1. 未持有效出入边界票据。。校验票据有效性 1 1.2. 从事与票据种类不符的活动的 2 1.3. 数据为数字的应该校验数字 2
  3. Atitit.月度计划日程表 每月流程表v5
  4. Atiti.ui原理与gui理论
  5. 跨语言传输调用对象.TXT
  6. 蚂蚁财富号:大、小型基金公司的电商业务对比
  7. 机器学习 --- 2. 从最大似然再看线性回归(转)
  8. 菜鸟的系统架构师如何应对交易系统激增的系统流量
  9. 【优化求解】基于matlab改进的遗传算法求解带约束的优化问题【含Matlab源码 1773期】
  10. 【元胞自动机】基于matlab元胞自动机双通道交通【含Matlab源码 1657期】