我们先看一下这几个sql在hive中的返回值:

  • hive中整数默认给int类型
  • 带有小数位的给double类型
  • 可以通过cast(num as decimal(n,m)) 指定数字类型
  • int类型是最弱的类型,它和其他两个操作后会被转换
  • double是最强的类型,和其他两个类型操作时会全部转换成dluble类型
  • 使用double运算时可能会导致精度丢失,如对精度要求较高,建议全都换成decimal类型之后再做操作。
select cast('0.00407' as decimal(18,6))*2500  --10.175
select cast('0.00407' as decimal(18,6))*cast(2500 as decimal(18,2))  --10.175
select cast('0.00407' as decimal(18,6))*cast(2500 as double)  -- 10.174999999999999 


explain select 200;  --返回值类型:int 
explain select 200.00;  --返回值类型:double 
explain select 200*200.00 --返回值类型:double
explain select 200*cast(200.00 as decimal(18,2)) --返回值类型:decimal 
explain select 200.00*cast(200.00 as decimal(18,2)) --返回值类型:double 

  • 两个declimal计算不会造成精度丢失
  • double和decimal计算可能造成精度缺失

1、hive将字符串默认转换成double类型进行计算

  • 执行一下代码:
--'0.00407' 是double,2500 是int类,结果是double类
explain select '0.00407'*2500  -->10.1749999999 
  • 执行计划
    在这里插入图片描述- 可以看到,hive将字符串 ‘0.0407’ 转换成 double类型,最终输出值是: 10.1749999999

2、将字符转换成decimal后再计算

  • 执行下面代码:
--2500 是int类型,和decimal类行计算后为 decimal 
explain select cast('0.00407' as decimal18,6))*2500   --> 10.175  
  • 执行计划
    在这里插入图片描述- 将字符串 ‘0.0407’ 转换成 decimal类型之后再计算,结果为: 10.175

decimal 运算先后导致的精度丢失

  • hive中即使数值都是decimal,也有可能造成精度缺失 。
  • 因为下一步的计算是以上一个计算结果为基础的,所以任何一部出现无法准确表达的数值时都可能造成精度缺失
select 100/12*6  --50.0 
select cast(100 as decimal(18,2))/12*6  --49.999998 
select cast(100 as decimal(18,2))/cast(12 as decimal(18,2))*cast(6 as decimal(18,2))  --49.999998
select cast(100 as decimal(18,2))*6/12  --50
  • 100 /12 *6 这算式在逻辑上与 100 * 6/12 和 100/2 等价,但是100/12不能尽除,导致中间出现中间值:8.33333333333333 导致最终结果丢失精度,结果为:49.999998
  • 对于decimal类型来说,计算时应尽量让乘法在除法前计算

总结

  • 虽然两个代码的返回值是:10.1749999999 、 10.175 看上去差异很小,但如果将数值通过round函数精确到两位数,则分别返回 10.1710.18 。在金融领域查一分钱的话还是需要注意的,很可能造成资金不对等。
  • hive中double和decimal两个类型计算会返回double,有可能造成精度缺失。应该把两个计算值都转换成decimal类型。
  • 对于decimal类型来说,计算时应尽量让乘法在除法前计算,减少中间值无法精确表示的情况。

高精度计算时,尽量多保留两位小数,并吧数据转换成decimal类型后再做计算,以免精度丢失

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐