从相差0.0000000000001说起,本文主要是对odps的Double和Decimal的精度使用问题做一个总结。
1. 问题描述
客户开发人员在使用maxcompute对double数据类型求和时出现错误(数据表由oracle数据库抽取到maxcompute, 对应字段类型为number到double),正确的结果是1943.38,但求和结果为1943.3799999999999,结果相差了0.0000000000001,这个差值的比例可以这样类比——如果地球的周长(40076.02千米)作为单位1的话,那么误差换算出来是4微米,差不多是一个红细胞的大小。绝大多数的情况下,我们可以忽略这个问题,但是在金融线,“差一微米也不行”。
2. 问题的根因:double求和带来精度问题
double适合做科学计算,如果用来进行精确计算,会带来精度丢失的问题。二进制的浮点数计算标准是IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现),double类型通常指“双精确度(64位)”,53位有效数字。要理解double的精度问题,我们从最基础的二机制与十进制转换看起,比如:如何用二进制表示0.1?小数是用整数除法来表示的,0.1=1/10(十进制)=1/1010(二进制),会得到一个除不尽的值,用double类型来表示这个数的时候就必须要进行截断(舍入),得到的结果是0.00011001100110011001100110011001100110011001100110011010,如果把结果转回十进制,会发现这个值已经不是0.1,精度问题产生了。同理,double类型在进行计算也会造成同样的精度问题。
3. 如何解决——double转型decimal
double计算会有精度问题,为了得到精确的结果,就要在计算之前进行处理,转换成无损计算的类型之后,再进行计算,maxcompute提供了这种无损类型——decimal。
3.1 double直接转成decimal再次遇到问题
不幸的是,直接转型会遇到以下两个问题:
1)转型也会有精度损失。
2)同列的某些值看起来没有精度损失,另一些有,出现表现不一致的情况。
图1
- double直接转decimal会带来精度损失,因为double的小数位有效位比decimal要少,decimal会对最后的几位进行随机数补齐,引入了精度问题。
- 同列中某些值没有出现任何精度损失,因为客户使用了2.0数据类型版本,在这个版本中maxcompute对转换进行了优化,对位数较小的数(测试结果为7位,供参考)采用了不同的转型算法(类似decimal的处理方法,转换成整数进行计算,保证无损)。位数较大的数无法采用该算法,标准算法处理,会出现精度损失。
4. 转换成decimal就大功告成了么?
4.1 incompatible type exception
decimal类型的计算虽然是无损的,但是decimal在计算过程可能会产生精度位数的变化,导致下图中的问题:计算结果插入结果表中时出现"incompatible type"的错误。
图2
4.2 如何避免
问题出现的原因是混用了1.0 decimal类型和2.0 decimal类型。若想有效的避免decimal计算导致的问题,需要遵循:
- 从建表开始,始终使用同一种数据类型,不要混用。
- 使用2.0数据类型,建源表和结果表时指定具体的decimal精度位,如decimal(35,6),避免计算中精度位数的变化。
5. 避免转型问题的最佳实践
如果希望避免精度问题,并且在计算过程中避免结果转型,那么可以将所有涉及精确计算的字段在建表时就采用2.0数据类型,并且指定所需要的精度,例如:
set odps.sql.decimal.odps2=true;
CREATE TABLE `ods_test` (
` account_balance` DECIMAL(38, 18) COMMENT '**余额'
)
在后续的查询和计算过程中,设置“odps.sql.decimal.odps2=true”后进行操作,例如:
set odps.sql.decimal.odps2=true;
select sum(account_balance) from ods_test
6. 写在最后
本篇主要讨论了计算(数据开发)过程中double类型精度问题,maxcompute在数据集成的过程中会不会产生精度问题?最佳实践是什么?预知后事如何,且听下回分解!
参考文档
[1] https://blog.csdn.net/liliuteng/article/details/8062019
[2] https://cloud.tencent.com/developer/article/1468551
[3] https://blog.csdn.net/lkforce/article/details/81564927
[4] https://www.zhihu.com/question/42024389/answer/93528601
[5] https://help.aliyun.com/product/27797.html?spm=a2c4g.11186623.6.540.615f44f675F7Wi
[6] https://baike.baidu.com/item/IEEE%20754/3869922?fr=aladdin
我们是阿里云智能全球技术服务-SRE团队,我们致力成为一个以技术为基础、面向服务、保障业务系统高可用的工程师团队;提供专业、体系化的SRE服务,帮助广大客户更好地使用云、基于云构建更加稳定可靠的业务系统,提升业务稳定性。我们期望能够分享更多帮助企业客户上云、用好云,让客户云上业务运行更加稳定可靠的技术,您可用钉钉扫描下方二维码,加入阿里云SRE技术学院钉钉圈子,和更多云上人交流关于云平台的那些事。