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

原文链接

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

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tcping命令详解

    tcping命令详解tcping命令用法以及帮助文档的各项参数的解释。

    2022年6月23日
    36
  • pychan激活码【在线注册码/序列号/破解码】

    pychan激活码【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    47
  • 文件包含漏洞—allow_url_fopen和allow_url_include详解

    文件包含漏洞—allow_url_fopen和allow_url_include详解文件包含漏洞_allow_url_fopen和allow_url_include详解提要:在文件包含漏洞中,PHP脚本环境中php.ini文件中通常会涉及到这两个参数,两个参数的开启或关闭影响文件包含漏洞的利用。1,参数简介:allow_url_fopen参数(只影响RFI,不影响LFI)简介:是否允许将URL(HTTP,HTTPS等)作为文件打开处理allow_url_include参数(只影响RFI,不影响LFI)简介:是否允许includeI()和require()函数包含URL(HTTP

    2022年7月16日
    13
  • Java高级工程师常见面试题(答案)[通俗易懂]

    Java高级工程师常见面试题(答案)[通俗易懂]Java高级工程师常见面试题2017年02月17日12:46:00阅读数:17280一、Java基础1.String类为什么是final的。   1.线程安全2.支持字符串常量池数据共享,节省资源,提高效率(因为如果已经存在这个常量便不会再创建,直接拿来用)  2.HashMap的源码,实现…

    2022年6月12日
    32
  • fopen 打开网址 设置php.ini,[教程] DreamHost修改php.ini来打开allow_url_fopen函数以支持采集…

    fopen 打开网址 设置php.ini,[教程] DreamHost修改php.ini来打开allow_url_fopen函数以支持采集…该楼层疑似违规已被系统折叠隐藏此楼查看此楼有时候发现空间不能采集,考虑一下是不是由于这个原因引起的,可以通过如下方法来尝试解决:1.首先用SSH登录空间2.在网站根目录建立建立cgi-bin文件夹#mkdir~/youdomain.com/cgi-binPS:youdoamin.com是你的域名目录名称或你自定义的目录名称。3.建立php_update.sh文件#vi~/youdom…

    2022年7月21日
    15
  • 按位异或的深入理解[通俗易懂]

    按位异或的深入理解[通俗易懂]异或运算:首先异或表示当两个数的二进制表示,进行异或运算时,当前位的两个二进制表示不同则为1相同则为0.该方法被广泛推广用来统计一个数的1的位数!参与运算的两个值,如果两个相应bit位相同,则结果为0,否则为1。即:  0^0=0,   1^0=1,   0^1=1,   1^1=0按位异或的3个特点:(1)0^0=0,0^1=1 0

    2022年6月6日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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