作者:蒋步星

来源:数据蒋堂

本文共1600字,建议阅读9分钟。
如何保证数据操作的精确度和高性能呢?

润乾研发部在招聘时有一个笔试题:

1/2, 1/5, 1/20, 1/64, 1/125都可以写成有限小数,而1/3, 1/7, 1/15, 1/24则必须写成无限循环小数。请指出能写成有限小数的分数具有什么样的特征?在什么情况下1/5也会被写成无限循环小数?

坦白地说,这个题的通过率并不高,不到一半吧。


仔细分析题目中的分母,我们会发现,这些能写成有限小数的分母,分解质因数之后就都只有2和5这两种质因子。而那些不能写成有限小数的分母分解因数后则含有不是2和5的质因子。也就是说,只有当分母可以写成2^n*5^m这种形式时才可能写成有限小数。

这是为什么呢?

其实很简单,因为我们把这些分数写成小数时使用的是10进制。而10=2*5,对于任何一个形如2^n*5^m的分母,设k=max(n,m),则把这个数乘以10^k,即2^k*5^k,就一定会变成一个整数了,也就是说,这个数的小数部分最多只有k位,这当然是有限的。而如果分母中含有其它质因子,则不可能有个k使得让这个数乘以10^k后变成整数,也就只能是无限小数了。


那么,什么时候1/5会写成无限小数呢?

如果我们采用的数制不是5的倍数,就会发现这种情况了,比如计算机普遍采用的2进制,这时候1/5会写成一个无限循环小数。

但是,我们的机器都是有限位数的,不可能真地表示一个无限位的数,只能舍弃后面的位。也就是说,1/5在计算机中是不能被精确表示的!


这个现象会影响到我们的程序设计。

比如我们写一段这样的代码:

double x = 0;

for ( int i=0; i<=1000; i++ )

x+=0.001;

我们现在想当然地认为x会等于1,然而并不是!在我的机器上的Java环境中跑出来x=1.0000000000000007,一个奇怪的结果。

为什么要强调的是我的机器上的Java环境呢?因为浮点数的表示和CPU以及编译器都有关系,换一台机器或编译器就可能会跑出不同的结果。

而且,结果也不总是变大。如果我们改成反复加1万次(即用i<=10000),得到的x=9.999999999999897,没啥规律可言。


计算结果和预期值的误差其实非常小,会有什么后果吗?

如果是用于后续再计算(比如再加减乘除等),这个误差确实不重要,可以不去理它。但有时候我们可能会把它用于比较,再根据比较结果做下面的动作。比如我们预期这个x应当等于1,如果后续是这样的代码:

if ( x==1.0 ) {…} else {…}

那就会执行出错误的结果了,这个bug还很难被发现,代码逻辑上看完全没有问题。而且由于前面所说的该现象出现的随机性,也不是对任何数都一定会产生这个结果,很可能在测试时没碰到而被放过了。


那么,怎么避免这个错误呢?

在涉及浮点数相等比较时,一般不要直接使用精确地相等去判断,而要看差的绝对值是否小于某个很小的数。代码写成:

if ( abs(x-1.0) < 1E-10) ….

就不会错了。

如果目标比较值是整数,那还可以将计算结果转换成整数,整数在2进制下都可以精确表示,可以放心地用==去判断,但注意要做四舍五入,即

if ( int(x+0.5) == 1 ) ….

如果直接用int(x)取整,在计算结果因舍位误差小于预期结果时,也会出错。

比较值不是整数,但能保证一定位数的精度,可以先用乘法再转换成整数:

if ( int(x*1000+0.5) == 1000 ) …


还有的办法就是避免使用浮点数。

我们知道,现代数据库都提供有decimal数据类型,其实就是这么个思路。decimal可以称为定点数,其小数部分也是按位数存储的,计算时能够精确表示,不会有上述的误差。

但是,decimal不是现代CPU直接支持的数据类型,需要数据库软件来自行实现其计算逻辑,性能就会差出很多。所以,在不需要这种精度时(比如只是计算总数或平均值等),我们还是把它转换成浮点数来计算更好一点。集算器在从数据库取数时提供了@d选项就是为了自动把decimal转成浮点数获得高性能,但需要冒不精确的风险,所以做成选项由程序员自行根据场景决定。

实际业务中,需要精确比较的浮点数常常是金额。大多数国家的货币都是两位小数的,这样我们可以将数值先乘以100转换成整数再存储,而整数的运算和比较都是精确的,不会出现这种问题,但是在显示时需要再转换回来变成用户习惯的两位小数写法。CPU计算和处理整数的性能也非常高,64位的CPU能够表示的整数范围在±2^63,即使除以100也还有16位整数部分,大约是1千万亿,这对于相当多的场景都够用了。这样就即有精确度又有高性能。

专栏作者简介

润乾软件创始人、首席科学家

清华大学计算机硕士,中国大数据产业生态联盟专家委员,著有《非线性报表模型原理》等,1989年,中国首个国际奥林匹克数学竞赛团体冠军成员,个人金牌;2000年,创立润乾公司;2004年,首次在润乾报表中提出非线性报表模型,完美解决了中国式复杂报表制表难题,目前该模型已经成为报表行业的标准;2014年,经过7年开发,润乾软件发布不依赖关系代数模型的计算引擎——集算器,有效地提高了复杂结构化大数据计算的开发和运算效率;2015年,润乾软件被福布斯中文网站评为“2015福布斯中国非上市潜力企业100强”;2016、2017年,荣获中国电子信息产业发展研究院评选的“中国软件和信息服务业十大领军人物”;2017年度中国数据大工匠、数据领域专业技术讲堂《数据蒋堂》创办者。

数据蒋堂

《数据蒋堂》的作者蒋步星,从事信息系统建设和数据处理长达20多年的时间。他丰富的工程经验与深厚的理论功底相互融合、创新思想与传统观念的相互碰撞,虚拟与现实的相互交织,产生出了一篇篇的沥血之作。此连载的内容涉及从数据呈现、采集到加工计算再到存储以及挖掘等各个方面。大可观数据世界之远景、小可看技术疑难之细节。针对数据领域一些技术难点,站在研发人员的角度从浅入深,进行全方位、360度无死角深度剖析;对于一些业内观点,站在技术人员角度阐述自己的思考和理解。蒋步星还会对大数据的发展,站在业内专家角度给予预测和推断。静下心来认真研读你会发现,《数据蒋堂》的文章,有的会让用户避免重复前人走过的弯路,有的会让攻城狮面对扎心的难题茅塞顿开,有的会为初入行业的读者提供一把开启数据世界的钥匙,有的甚至会让业内专家大跌眼镜,产生思想交锋。

数据蒋堂第二年往期回顾:

数据蒋堂 | 莫非我就是被时代呼唤的数学人

数据蒋堂 | SQL是描述性语言?

数据蒋堂 | 存储和计算技术的选择

数据蒋堂 | 人工智能中的“人工”

数据蒋堂 | 中国报表漫谈

数据蒋堂 | 内存数据集产生的隐性成本

数据蒋堂 | 多维分析预汇总的功能盲区

数据蒋堂 | 多维分析预汇总的存储容量

数据蒋堂 | 多维分析预汇总的方案探讨

数据蒋堂 | 数据库的封闭性

数据蒋堂 | 内存数据集产生的隐性成本

数据蒋堂 | 前半有序的大数据排序

数据蒋堂 | “后半”有序的分组

数据蒋堂 | 时序数据从分表到分库

数据蒋堂 | BI系统的前置计算

数据蒋堂 | 性能优化是个手艺活

数据蒋堂 | 数据分布背后的逻辑

数据蒋堂 | 从一道招聘考题谈起相关推荐

  1. 数据蒋堂 | BI系统中容易被忽视的数据源功能

    作者:蒋步星 来源:数据蒋堂 本文共1100字,建议阅读8分钟. 关注BI系统数据源有关的后台功能点. 用户在选购BI解决方案的时候,常常会更关注界面环节的功能指标,比如美观性.操作的流畅性.移动端支 ...

  2. 数据蒋堂 | 做基础软件要投入很多钱?

    作者:蒋步星 来源:数据蒋堂 本文共1100字,建议阅读8分钟. 看起来还真是,似乎还要再加大投入才行? 现在有个说法,国家对基础软硬件的投入太少,经常会说微软.Oracle.Intel这些巨头每年的 ...

  3. 数据蒋堂 | 大数据技术的4个E

    作者:蒋步星 来源:数据蒋堂 本文共1100字,建议阅读8分钟. 本文将大数据特点总结成4个E,可作为选择大数据技术解决方案的参考. 大数据的4个V说法在业界已经尽人皆知,这是指的大数据本身的特征.现 ...

  4. 数据蒋堂 | 大清单报表的打印?

    作者:蒋步星 来源:数据蒋堂 本文共900字,建议阅读5分钟. 报表打印也需要做一个缓存机制吗? 上一期文章<大清单报表应当怎么做?>中,我们谈了大清单报表的呈现方法,其实有时候这些报表还 ...

  5. 数据蒋堂 | 数据压缩手段

    作者:蒋步星 来源:数据蒋堂 本文共2600字,建议阅读9分钟.如果能物理地减少数据存储量,也就自然而然地减少了外存访问量. 我们知道,外存(硬盘)的性能远远低于内存,即使是同样复杂度的运算(CPU计 ...

  6. 数据蒋堂 | 怎样生成有关联的测试数据

    作者:蒋步星 来源:数据蒋堂 本文共1500字,建议阅读7分钟. 如何在多表情况下生成大规模测试数据时还能保证合理的关联性呢? 在向用户推荐新的数据处理技术,特别是涉及性能优化的场景时,经常会碰到生成 ...

  7. 数据蒋堂 | 内置的数据无法实现高性能

    作者:蒋步星 来源:数据蒋堂 本文共1400字,建议阅读7分钟. 获得了数据库的方便性就得不到高性能,要数据外置的高性能就要牺牲方便性. 这里说的"内", 是指数据库之内. 当数据 ...

  8. 数据蒋堂 | 报表工具的SQL植入风险

    作者:蒋步星 来源:数据蒋堂 本文共2600字,建议阅读10分钟. 报表开发人员如何规避安全漏洞问题? 所有的报表工具都会提供参数功能,主要都是用于根据用户输入的查询条件来选取合适的数据.比如希望查询 ...

  9. 数据蒋堂 | 为什么我们需要C程序员

    作者:蒋步星 来源:数据蒋堂 本文共1000字,建议阅读6分钟. 如何保证数据操作的精确度和高性能呢? 再说一个招聘的话题. 大家可能知道,润乾的软件产品主体都是Java写的,几乎没有别的语言.但是, ...

最新文章

  1. python学好了能干什么-Python语言能做什么,学好能干什么
  2. C#路径/文件/目录/I/O常见操作汇总(一)
  3. 全球及中国USB分路器行业发展布局与应用现状调研报告2022年
  4. NOJ 20 吝啬的国度
  5. 看文艺青年怎么玩微信客户端
  6. 恢复被CVS被Override and Update后的代码
  7. 活动目录组策略统一管理桌面
  8. 基于opencv的gpu与cpu对比程序,代码来自opencv的文档中
  9. BNU44583——Star Trek: First Contact——————【01背包】
  10. python百度百科-python语言是由哪个人创造的
  11. matlab leslie模型,【2017年整理】leslie人口增长模型模型.doc
  12. 东软实训告诉你:职场上不该说的13种话
  13. PX4固定翼姿态控制器详细介绍(一)
  14. 刚刚,联通和华为发布《5G车路协同白皮书》| 附下载
  15. kali Linux的 安装详细步骤
  16. 我大121321321321321
  17. HSE\HEI\PLL\LSE\LSI
  18. 中控百傲瑞达系统说明书_百傲瑞达一卡通系统.PDF
  19. 魔方玩家的执念采用Python、Java、Android实现的三阶魔方打乱功能
  20. 快递100开放快递查询接口

热门文章

  1. 中介者模式 调停者 Mediator 行为型 设计模式(二十一)
  2. sql建表,建索引注意事项
  3. 广州企业“掘金”物联网蓝海
  4. ebuild 中的软件包依赖
  5. Android 侧划菜单
  6. C# socket编程实践——支持广播的简单socket服务器
  7. java和C++ C比较
  8. python 字典操作 内存占用,python - 如何强行释放字典使用的内存? - SO中文参考 - www.soinside.com...
  9. mysql反掩码_ACL规则 反掩码的 写法
  10. 排序算法一:选择排序