浮点数的那点事

浮点数是计算机中储存实数的形式。我们时常需要用浮点数去处理带小数点的运算。可你是否知道,浮点数还有这些操作:

正负无穷大

与整数不同,浮点数没有溢出的概念。当浮点数的运算结果超过一定范围时,它的值就会根据运算结果的符号变成正无穷大或负无穷大。最简单产生无穷大的运算就是除以0.例如1.0/0.0的结果是正无穷大,而-1.0/0.0的结果是负无穷大。注意:浮点数除于0不会产生错误,只有整数才会。

无穷大的性质和你想象中的一样:除了无穷大自身和后面要提到的NaN外,任何一个浮点数都小于正无穷大,大于负无穷大。而且无穷大加、减、除一个非无穷大,或乘一个非0数的结果都是无穷大(可能变号)。

无穷大在一些特定情况很有用。比如说,你要找xx的最小值时,你可以把储存最小值变量初始化为无穷大。或者,你也可以用无穷大的代价表示无解。

NaN

NaN是浮点数中一个有毒的常量。它满足很多奇葩的性质。

NaN是Not a Number的缩写。也就是说,NaN表示它不是一个数字。浮点数中居然有一个“不是数字”的“数字”,究竟是几个意思呢?

首先,我们看看NaN是怎么产生的。NaN对应着数学中的“不定式”,例如0.0/0.0,(1.0/0.0 - 1.0/0.0)(即无穷大减无穷大),0.0*(1.0/0.0)(即0乘以无穷大)等。也就是说,当运算结果不能确定时,它就干脆直接给你一个“不是数字”。

由于NaN不是数字,它满足很多毁三观的性质,其中一个标志性的性质,就是它与任何数字都不相等,包括它自己!

所以,当x取NaN时,x == x为false!

这是判断一个浮点数是不是NaN的常用方法。事实上,除了!=的结果永远是true以外,NaN与任何浮点数的所有大小比较都是false。而且,NaN和任何浮点数的运算(即加减乘除等)结果都是NaN。

由于NaN的性质如此有毒,它很容易造成各种bug。例如,如果你不小心计算了无穷大减无穷大,你就得到NaN。由于它的所有比较都是false,你的程序会出现奇怪的行为,让你百思不得其解。

还有就是,如果你看到如下if语句

if (x < 1.2) {
    // Do something
} else if (x >= 1.2) {
    // Do something
}

你可能以为else后面那个if语句是多余的。其实不然。这个if起到了排除NaN的作用。尤其是当x是函数参数的时候,如果参数传入一个NaN,你要能正确处理它。

当然,NaN也有一定的正面作用。例如我们可以用NaN来表示“无解”或者“不存在”等性质。我们也可以利用它和任意数字不相等这一性质来提供便利。例如如果我们想从浮点数组中删除一个数字,我们可以把它设为NaN。特别的,在C++中我们可以用memset(arr, 0xFF, sizeof(arr))将浮点数组初始化为NaN。

精度误差

由于储存空间有限,我们不可能将一个实数,尤其是无限小数的精确值储存下来。这样,在运算过程中就会产生精度的误差。

我们不妨看这样一段代码:

for (int i = 1; i < 100; ++i) {
    double a = 1.0/i;
    if (a*i != 1.0)
        cout << " " << i;
}
cout << endl;

假如没有精度误差,上面这段程序应该什么都不输出。但实际上它会输出49和98。这是精度误差导致的相等判断错误。

所以,两个浮点数是否相等并不能直接判断,而应该用两个数的差的绝对值小于一个很小的数(例如1e-7,7代表精确的小数位数)作为条件来进行判断。

const double eps = 1e-7;
cout << "inexact result with double:";
for (int i = 1; i < 100; ++i) {
    double a = 1.0/i;
    if (!(fabs(a*i - 1.0) < eps))
        cout << " " << i;
}

这段代码就不会有任何输出了。

时间: 2024-08-24 20:51:00

浮点数的那点事的相关文章

数字、基数及表示

数字.基数及表示 整数 整数是这些熟悉的数字 …, -1, 0, +1, +2, ….整数值也被称作是‘完整的’,并且分为正数(1到无穷大),负数(-1到负无穷大),零(0),非负数(零或正数)和少有的非正数(零或负数).正数和非负数间的差别通常非常重要,例如C语言典型地用非负数作为数组下标,明确地包括零. 基数 我们书写整数(和其它数字)时通常使用‘基数10’或‘十进制’算术.这是一种位置符号,每一个‘位置’的值比下一个大十倍.最后一个数字是一的个数,倒数第二个是10的个数,依此类推:因此数字

java解惑之常常忘记的事

java解惑之常常忘记的事 2012-10-17 18:38:57|  分类: JAVA |  标签:基础知识  软件开发  |举报|字号 订阅 针对刚接触java的菜鸟来说,java基础知识都是我们必须认真学习的,但是在工作过几年时间的老鸟来说,有时候也会对java的基础知识产生疑问,对于这种不确定,并且很容易混淆的知识点,java解惑已经为大家进行了很好的总结,现在借用一个作者的总结,进行一下罗列,希望能对你有所帮助. 1. 奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为i

C++的那些事:流与IO类

1.流的概念 "流"就是"流动",是物质从一处向另一处流动的过程,比如我们能感知到的水流.C++的流是指信息从外部输入设备(如键盘和磁盘)向计算机内部(即内存)输入和从内存向外部输出设备(如显示器和磁盘)输出的过程,这种输入输出过程被形象地比喻为"流". 为了实现信息的内外流动,C++系统定义了I/O类库,其中的每一个类都称作相应的流或流类,用以完成某一方面的功能.根据一个流类定义的对象也时常被称为流. 通常标准输入或标准输出设备显示器称为标准流

【C语言探索之旅】 第一部分第五课:运算那点事

内容简介 1.课程大纲 2.第一部分第五课:运算那点事 3.第一部分第六课预告:条件表达式 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型 文件读写

浮点数在内存中的表示

        1. 浮点数的二进制格式. 浮点数的二进制格式如下, 分为 3 个部分, 即 sign (符号位), exponent (指数位), 以及 significand (有效数位). 如下图所示: single-precision floating point(单精度浮点数), 4 字节, 共 32 位: 31            23   22                               0         +---------------------------

(小说)那些年,那些事——一个程序员的奋斗史

转自:http://blog.csdn.net/x283930450/article/details/9072223 第01章    段伏枥,一个瘦小,矮小,根本和“帅”这个字粘不上任何关系的普通人 .名字的来源在于其多读了几年书的老爹,总抱着有一天要出书出名乃至于名流千古的 美好理想,但可惜现实总是给予他无情的而又现实的打击,于是就将理想寄望于自己的 儿子,起了个“伏枥”的名,寓意为“老骥伏枥,志在千里”,表达自己不到黄河不死 心的良好的愿望.     只可惜段伏枥这家伙完美地遗传了来自于老爹

Python3.2官方文档翻译-列表工具和十进制浮点数计算

Disk Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2368    Accepted Submission(s): 333 Problem Description 有很多从磁盘读取数据的需求,包括顺序读取.随机读取.为了提高效率,需要人为安排磁盘读取.然而,在现实中,这种做法很复杂.我们考虑一个相对简单的场景.磁

浮点数的输入以及浮点数运算

写在前面 上一次我们讲解了IEEE的标准,还记得多少? 之前我提到过,有很多小数是二进制浮点数无法表示的,因此就难免会遇到舍入的问题.这一点其实在我们平时的计算当中会经常出现,就比如我们之前提到过的0.3,就无法使用浮点小数来准确表示. 我使用C#写了一个程序,打印出0.3的二进制表示,是这样的一个数字:0 01111101 00110011001100110011010.不信没关系,用我昨天说的那个公式计算一下啊.这个二进制数大概是多少,它的阶码在偏置之后的值为-2,它的尾数位在加1之后为1+

二进制那些事

理清字符集和字符编码关系中介绍到计算机内部由集成电路决定了计算机的信息只能用二进制数处理.本期将介绍二进制那些事. 移位运算 移位运算指的是将二进制数值的各数位进行左右移位的运算.左移空出来的低位要进行补0操作,右移空出来的高位要进行怎样的操作,我们会在后面说明. 我们发现,左移两位相当于对39乘以4,右移两位相当于除4,也就是说计算机用移位算法来表示数据的乘除运算. 补数 刚才之所有没有介绍相关右移的内容,是因为用来填充右移后空出来的高位的数值,有 0 和 1 两种形式.要想区分什么时候补0什