首先,为啥会要讨论这个问题。

我得为昨天拖了小组后腿深表歉意。其实程序逻辑很快就理通了的,但自己总是会因为各种各样的小问题束缚手脚,看接下来这个图片:

稍微有数据敏感性的同学就能看出,中间这么一大堆又是0000又是999还是这么多位的小数,一看就是异常数据。这块数据的产生,源于代码里对两个字符串做了float转换并相减,导致出现了这种数据异常的错误。那么问题来了,1.这种异常是如何产生的?2.有哪些方法可以解决这种问题呢?3.编程中间还有哪些与这个问题相关的注意事项呢?

第一部分:这种异常是如何产生的呢?

我们先来看演示:

看来,直接输出float型数据,以及对字符串进行的float转换,本身并没有什么问题,那么为什么浮点数相减就会出现这个可恶的小尾巴呢?我们有必要从计算机本身数字加减的机制进行探究。有学习过《计算机组成原理》等基本课程、哪怕只是简单了解计算机内部运行机制的同学都明白,计算机内部的加减乘除都是要把数字转化成为二进制实现的。那么,我们此处的浮点数,也要转换为二进制,才能进行计算。Python内浮点数是用机器上浮点数的本机双精度(64 bit)表示的。提供大约17位的精度和范围从-308到308的指数。和C语言里面的double类型相同【可参考C语言double类型的解释】。

我们来看一个简单的例子。十进制1.1转换成二进制是什么数?十进制整数部分转化成二进制,用短除法处以2倒序取余。小数部分转化为二进制是用乘法乘2正序取整。见下面一个浮点数转二进制数的例子。

1.10整数部分就是1,转换成二进制1(这里整数转二进制不再赘述)
小数部分:0.1
0.1*2=0.2取整数部分0,基数=0.2
0.2*2=0.4取整数部分0,基数=0.4
0.4*2=0.8取整数部分0,基数=0.8
0.8*2=1.6取整数部分1,基数=1.6-1=0.6
0.6*2=1.2取整数部分1,基数=1.2-1=0.2
0.2*2=0.4取整数部分0,基数=0.4
.
.
.
直至基数为0。1.1用二进制表示为:1.000110...xxxx....(后面表示省略)

关于之前的演示,相当于,因为3.4的存储,发生了精度损失(3.5不会,因为3.5的二进制是11.1,补码存储依然不会发生精度损失),所以在相减的时候,发生了一次精度损失,最后结果存储的时候,再次发生一次精度损失。所以,才会出现最后的小尾巴情况。

第二部分:有哪些方法可以解决这个问题呢?

解决这个问题?不存在的,除非是提高精度——让计算机内能够完整的存储数字的二进制(二进制补码)表示,否则的话,只要有精度损失,就指不定什么时候会冒出来小尾巴。我们追求的解决,自然也是从提高精度,和“表面看起来正确”这两条道路去追求。

提高精度——Python本身自带的float已经是可支持浮点数的最高精度形式。当然,这个肯定是不能阻挡我们对更高精度的要求,这里可以自己实现高精度的数据形式,也可以使用Python扩展模块:Decimal。使用Decimal本身需要导入decimal包,初始化decimal数据可以使用整型数据和字符串,而不能使用float型数据,正如之前我们所说的那样,某些浮点数存储会发生精度损失——这意味着float本身就不够精确。

当然,还有很多抖机灵的方法,比如说结果转换成字符串然后再截取?!

你可能体会不到,这个是一种针对数据波动范围相对确定,相当实用的方法——虽然应该没有任何一个脑子正常的程序员会推崇这种方法。这种方法就是追求的“表面上看起来正确”,你看,最后的显示出来的结果不就是-0.1么?

自然,还有print的%精度控制,这里就不赘述。而且也不想详述这个,毕竟这个惊为天人的字符串截取方法,都还是对字符串进行了处理,而%精度控制只是显示的时候做了处理,可真是够“表面”的。

不得不说,也是受这种方法的启发,本人使用的方法,是利用Python int转换“舍去小数点后所有数字”的特点,把原浮点数乘以需要保留精度的位数,然后转换成整数,再除回去,这样就形成了“表面正确”的数据,效果不要太好。

总结一下!解决这个精度损失带来的“恶魔小尾巴”问题,我们大体上有提高数据格式精度和只追求最终显示改变两大思路。

提高数据格式精度:使用扩展包decimal

只追求最终显示改变:printf %精度控制 ,字符串截取指定位数,先移动小数点、转换成整型舍去末尾、再把小数点移动回来。等方法。

第三部分:编程中间还有哪些和这个问题相关的注意事项呢?

这个小尾巴让我可谓一开始是焦头烂额,也严重耽误了小组研究进度。通过我们之前的探究,可以发现,浮点数本身表示由于受计算机限制,经常是不精确的。所以,日常数据中,最好不要用浮点数。

可能有些人觉得精度损失一些没有什么,然而浮点数的精度损失关键时候可不只只是精度损失,甚至会影响流程控制!浮点数不只有Python里面有,咱们用更加基本的C++来说明这个问题:

当精度损失已经让程序的走向开始不符合逻辑的时候,你还会轻视这个问题么?

这里给广大同仁们分享一篇专门讲解浮点数的文章,深入了解,真的有很多可圈可点之处!

深入了解计算机浮点数机制——程序员必备!

【小思考】Python的float转换精度损失所想到的的更多相关文章

  1. Python之☞float浮点数精度问题

    Python的浮点数损失精度问题(转) 一个简单的面试题: >>>0.1+0.1+0.1 0.2 >>>0.1+0.1+0.1 0.3000000000000000 ...

  2. java学习笔记(3)数据类型、源码、反码、补码、精度损失、基本数据类型互相转换

    关于java中的数据类型: 1.数据类型的作用是什么? 程序当中有很多数据,每一个数据都是有相关类型的,不同数据类型的数据占用的空间大小不同. 数据类型的作用是指导java虚拟机(JVM)在运行程序的 ...

  3. WebGL着色器32位浮点数精度损失问题

    问题 WebGL浮点数精度最大的问题是就是因为js是64位精度的,js往着色器里面穿的时候只能是32位浮点数,有效数是8位,精度丢失比较严重. 这篇文章里讲了一些处理方式,但是视坐标这种方式放在我们的 ...

  4. Java中关于 BigDecimal 的一个导致double精度损失的"bug"

    背景 在博客 恶心的0.5四舍五入问题 一文中看到一个关于 0.5 不能正确的四舍五入的问题.主要说的是 double 转换到 BigDecimal 后,进行四舍五入得不到正确的结果: public ...

  5. Java double和 float丢失精度问题

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt357 由于对float或double 的使用不当,可能会出现精度丢失的问题. ...

  6. java float double精度为什么会丢失?浅谈java的浮点数精度问题 【转】

    由于对float或double 的使用不当,可能会出现精度丢失的问题.问题大概情况可以通过如下代码理解: public class FloatDoubleTest { public static vo ...

  7. double float的精度问题

    三部曲 1: #include <iostream> #include <stdio.h> #include <string.h> using namespace ...

  8. Java中的小数运算与精度损失

    float.double类型的问题 我们都知道,计算机是使用二进制存储数据的.而平常生活中,大多数情况下我们都是使用的十进制,因此计算机显示给我们看的内容大多数也是十进制的,这就使得很多时候数据需要在 ...

  9. JAVA浮点数计算精度损失底层原理与解决方案

    浮点数会有精度损失这个在上大学的时候就已经被告知,但是至今完全没有想明白其中的原由,老师讲的时候也是一笔带过的,自己也没有好好琢磨.终于在工作的时候碰到了,于是google了一番. 问题: 对两个do ...

随机推荐

  1. Bzoj1939 [Croatian2010] Zuma

    Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 43  Solved: 31 Description 有一行 N 个弹子,每一个都有一个颜色.每次可以让超过 ...

  2. 一个菜鸟的ASP.NET观光路线图

           作为一个成长的"菜鸟".我的习惯是,每过一个阶段,都对自己的知识体系进行一次概括. 这篇博文是一个总结帖,我将把我的学到的东西,按照一定顺序串联在一起.        ...

  3. 【转】C# Graphics类详解

    Brush 类 .NET Framework 4 定义用于填充图形形状(如矩形.椭圆.饼形.多边形和封闭路径)的内部的对象. 属于命名空间:  System.Drawing 这是一个抽象基类,不能进行 ...

  4. 20165320 实验一 java环境的熟悉

    实验内容与步骤 一.java开发环境的熟悉 1.建立一个有关自己学号的目录 2.在当前文件下编译一个带包Hello.java文件 3.代码内容 package sq; import java.util ...

  5. 20165230 《Java程序设计》实验二(Java面向对象程序设计)实验报告

    20165230 <Java程序设计>实验二(Java面向对象程序设计)实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:田坤烨 学号:20165230 成绩: ...

  6. Python使用OpenCV实现简单的人脸检测

    文章目录: OpenCV安装 安装numpy 安装opencv OpenCV使用 OpenCV测试 效果图: 注意: 图片人脸检测 程序要求: 技术实现思路 注意 本文使用的环境是:Windows+P ...

  7. codepage 和 charset

    codepage:简单地说,这是程序用于对字符进行编码的一个表.代码页是服务器的事情. 常见的三种codepage 简体中文 : 936 繁体中文 : 950 UTF-8 : 65001 如果你不想用 ...

  8. elasticsearch6.5集群环境搭建的一些坑

    都说el配置很简单,确实比solr简单多了,不用手动配置一大堆,不过第一次配置也不轻松,因为马虎老是漏掉了许多地方 配置一个半小时才启动成功: 这里主要记录一下一些遇到的坑: 一 不能用root启动, ...

  9. LCD时序中设计到的VSPW/VBPD/VFPD/HSPW/HBPD/HFPD总结【转】

    转自:https://blog.csdn.net/u011603302/article/details/50732406 下面是我在网上摘录的一些关于LCD信号所需时钟的一些介绍, 描述方式一: 来自 ...

  10. pom可以过滤resource 下的文件