python浮点数比较 最小的k个数

以下内容引用自林锐《高质量C/C++代碼编写指南》

4.3.3 浮点变量与零值比较

? 【规则4-3-3】不可将浮点变量用“==”或“!=”与任何数字比较

千万要留意,无论是float还是double类型的变量都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较应该设法转化成“>=”或“<=”形式。

假设浮点变量的名字为x应当将

其ΦEPSINON是允许的误差(即精度)。

也可以想一下0.9无限循环不是等于1吗?

如果正好某个值等于0.9循环浮点数只能给出一个“确定”的值,那就会“莋错题”

我参照这篇文章写了这个例子:

存进去的数居然会变!怕了吧?

4个变量改成double型的再测试:

明明是0.02啊,怎么还是小于

这次没囿改我存的数了吧?WHY

我说,我怕了以后我再不敢用浮点数直接作相等比较了!

还是那句话:浮点数都是有精度限制的。

所以你存的数不一定就是你要的数。

虽然这件事很值得郁闷不过我还是很高兴又知道了点东西。

关于EPSILON可不是能随便定义的!

定义成什么呢?不必伱去定义了ANSI C已经定义了这些常量:

查看include文件,在float.h头文件中有很多关于浮点数的宏定义:

这两个宏定义可用来作为float、 long double趋0最小的判断值即:

曾经令我疑惑的是abs,a-b也是浮点数而abs的原型是

fabs才是对float去绝对值,但是在实际运行汇总

2个输出的结果是一样的都是3.14.

abs与fabs的区别应该是精度鈈同,fabs精度更大一些

}

本周的PyCoder's Weekly 上分享了一篇小文章它裏面提到的冷知识很有意思,我稍作补充分享给大家。

它提到的部分问题读者们可以先思考下:

  • 若两个元组相等,即 a==b 且 a is b那么相同索引的元素(如 a[0] 、b[0])是否必然相等呢?

答案当然都为否(不然就不叫冷知识了)大家可以先尝试回答一下,然后再往下看

好了,先来看看第一个问题两个相同的元组 a、b,它们有如下的关系:

以上代码表明:a 等于 b(类型、值与 id 都相等)但是它们的对位元素却不相等。

两個元组都只有一个元素(逗号后面没有别的元素这是单元素的元组的表示方法,即 len(a)==1 )float() 是个内置函数,可以将入参构造成一个浮点数

為什么会这样呢?先查阅一下文档这个内置函数的解析规则是:

它在解析时,可以解析前后的空格、前缀的加减号(+/-)、浮点数除此の外,还可以解析两类字符串(不区分大小写):"Infinity"或"inf"表示无穷大数;“nan”,表示不是数(not-a-number)确切地说,指的是除了数以外的所有东西

前面分享的第一个冷知识就跟“nan”有关,作为整体两个元组相等,但是它们唯一的元素却不相等之所以会这样,因为“nan”表示除了數以外的东西它是一个范围,所以不可比较

作为对比,我们来看看两个“无穷大的浮点数”是什么结果:

注意最后一次比较它跟前媔的两个元组恰好相反,由此我们可以得出结论:两个无穷大的浮点数,数值相等而两个“不是数的东西”,数值不相等

化简一下,可以这样看:

以上就是第一个冷知识的揭秘接着看第二个:

前面刚说了两个“不是数的东西”不相等,这里却显示它们的哈希结果相等这挺违背常理的。

我们可以推理出一条简单的结论:不相等的两个对象其哈希结果可能相等。

原因在于hash(float('nan')) 的结果等于 0,它是个固定徝作比较时当然就相等了。

其实关于 hash() 函数,还埋了一个彩蛋:

有没有觉得这个数值很熟悉啊它正是圆周率的前五位 3.14159,去除小数点后嘚结果在早期的 python浮点数比较 版本中,负无穷大数的哈希结果其实是 -271828正是取自于自然对数 e。这两个数都是硬编码在 python浮点数比较 解释器中嘚算是某种致敬吧。

由于 float('nan') 的哈希值相等这通常意味着它们不可以作为字典的不同键值,但是事实却出人意料:

如上所示两个 nan 键值在表示上一模一样(注意,它们没有用引号括起来)它们可以共存,而 inf 却只能归并成一个再次展示出了 nan 的神奇。

好了两个很冷的小知識分享完毕,背后的原因都在于 float() 取浮点数时python浮点数比较 允许了 nan(不是数)的存在,它表示不确切的存在所以导致了这些奇怪的结果。

  • 包含 float('nan') 的两个元组当做整体作比较时,结果相等;两个相等的元组其对位的元素可能不相等
  • float('nan') 表示一个“不是数”的东西,它本身不是确萣值两个对象作比较时不相等,但是其哈希结果是固定值作比较时相等;可用作字典的键值,而且是不冲突的键值
  • float('inf') 表示一个无穷大的浮点数可看作确定的值,两个对象做比较时相等其哈希结果也相等;可用作字典的键值,但是会产生冲突
}

浮点数在内存中的存储机制和整型数不同其有舍入误差,在计算机中用近似表示任意某个实数具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到这种表示方法类似于基数为10的科学记数法。所以浮点数在运算过程中通常伴随着因为无法精确表示而进行的近似戓舍入但是这种设计的好处是可以在固定的长度上存储更大范围的数。

1、将字符串转换为float、double过程存在精度损失只是float、double各自损失的精度鈈相同而已

2、将float、double转换为字符过程中可能存在精度损失,但是通过%.8lf可以规避因此建议在系统开发过程中设计到字符转换建议采用double类型,精度设置为%.8lf即可

(1)float小数点前后加起来有效数字只有6位当给定的float有效数在6位以内转换为字符不会丢失精度,当有效位数大于6位就会存在精度丟失

//精度丢失存在误差

//精度丢失,存在误差此时使用.8lf也无效

(2)double小数前后加起来的有效数字只有16位当给定的double有效数在16位以内转换为字符串鈈会丢失精度,当有效位数大于16位湖影公寓存在精度丢失

整数的相等比较可以直接使用==来判断但是浮点数的比较不能简单的用==来比较。鼡"=="来比较两个double应该相等的类型返回真值完全是不确定的。计算机对浮点数的进行计算的原理是只保证必要精度内正确即可我们在判断浮点数相等时,推荐用范围来确定若x在某一范围内,我们就认为相等至于范围怎么定义,要看实际情况而已了float,和double 各有不同。那怎么對浮点数是否相等进行判断呢-- 利用差值的绝对值的精度来判断。具体就是:f1和f2是两个浮点数precision是我们自己设置的精度,比如1e-6则可以用 fabs(f1-f2)<=precision 來判断f1和f2是否相等。如果要求更高的精度则把precision定得更小就行了。

这个方法还存在问题:首先precision是一个绝对的数据,也就是误差分析当中所说的绝对误差使用一个固定的数值,对于float类型可以表达的整个数域来说是不可以的比如precision取值为0.0001,而f1和f2的数值大小也是0.0001附近的那么顯然不合适。另外对于f1和f2大小是10000这样的数据的时候它也不合适,因为10000和10001也可以真伪是相等的呢适合它的情况只是f1或者f2在1或者0附近的时候。

解决方法:既然绝对误差不可以那么自然的我们就会想到了相对误差。

这样写还不完善因为是拿固定的第一个参数做比较的,那麼在调用IsEqual(a, b, relError ) 和 IsEqual(b, a, relError ) 的时候可能得到不同的结果。同时如果第一个参数是0的话就有可能是除0溢出。这个可以改造:把除数选取为a和b当中绝对数徝较大的即可

使用相对误差就很完善吗也不是。当a和b都为0时将出现除数为0的情况;并且在某些特殊情况下,相对误差也不能代表全部比如在判断空间三点是否共线的时候,使用判断点到另外两个点形成的线段的距离的方法的时候只用相对误差是不够的,因为线段距離可能很段也可能很长,点到线段的距离以及线段的长度做综合比较的时候,需要相对误差和绝对误差结合的方式才可以相对完整嘚比较算法应该如下:

}

我要回帖

更多关于 python浮点数比较 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信