ODPS double类型转型精度问题总结

ODPS double类型转型精度问题总结简介:ODPSdouble类型转型精度问题总结从相差0.0000000000001说起,本文主要是对odps的Double和Decimal的精度使用问题做一个总结。1.问题描述客户开发人员在使用maxcompute对double数据类型求和时出现错误(数据表由oracle数据库抽取到maxcompute,对应字段类型为number到double),正确的结果是1943.38,但求和结果为1943.3799999999999,结果相差了0.0000000000001,这个…

大家好,又见面了,我是你们的朋友全栈君。

简介: ODPS double类型转型精度问题总结

 

image.png

 

从相差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)同列的某些值看起来没有精度损失,另一些有,出现表现不一致的情况。

 

image.png

 

  • double直接转decimal会带来精度损失,因为double的小数位有效位比decimal要少,decimal会对最后的几位进行随机数补齐,引入了精度问题。
  • 同列中某些值没有出现任何精度损失,因为客户使用了2.0数据类型版本,在这个版本中maxcompute对转换进行了优化,对位数较小的数(测试结果为7位,供参考)采用了不同的转型算法(类似decimal的处理方法,转换成整数进行计算,保证无损)。位数较大的数无法采用该算法,标准算法处理,会出现精度损失。

4. 转换成decimal就大功告成了么?

4.1 incompatible type exception

decimal类型的计算虽然是无损的,但是decimal在计算过程可能会产生精度位数的变化,导致下图中的问题:计算结果插入结果表中时出现”incompatible type”的错误。

 

image.png

 

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服务,帮助广大客户更好地使用云、基于云构建更加稳定可靠的业务系统,提升业务稳定性。

原文链接

本文为阿里云原创内容,未经允许不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/162210.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号