【MaxCompute学习】隐式转化的问题

来源:互联网 发布:nginx flask windows 编辑:程序博客网 时间:2024/06/05 15:29

有一次计算一个数据的百分比,想把小数结果取2位,并拼接一个百分号展示在结果报表中。用到的sql如下

select concat(round(10230/1497409,4)*100,'%') from  dual;

很奇怪局部数据并没有保留2位小数,比如上面的数据返回的是67.99999999999999

我计算了下上面的结果大概得到的数据为0.0068

select concat(round(0.0066 ,4)*100,'%') from  dual;--0.66%select concat(round(0.0067 ,4)*100,'%') from  dual;--0.67%select concat(round(0.0068 ,4)*100,'%') from  dual;--0.6799999999999999%select concat(round(0.0069 ,4)*100,'%') from  dual;--0.69%

由于计算值采用了concat函数,concat的多个参数为string类型,如果输入为bigint,decimal,double,datetime类型会隐式转化为string类型,并且返回的为string类型

也就是说有两种情况

1.round函数返回的数字cast为string后就丢失了精度。 2.round函数返回的数字就丢失了精度。

select round(0.0066 ,4)*100 from dual; --0.66select round(0.0067 ,4)*100 from dual; --0.67select round(0.0068 ,4)*100 from dual; --0.6799999999999999select round(0.0069 ,4)*100 from dual; --0.69

上面的结果说明是round函数返回的数字就丢失了精度。

round函数是用来计算指定到小数点位数的四舍五入的值的,如果其第一个参数为double类型,那么函数计算的结果就是double类型,如果其第一个参数为Decimal类型,那么函数计算的结果就是decimal类型的,如果其第一个参数为string类型或者bigint类型,那么就会隐式转化为double类型。

单独计算round的返回值如下,说明double类型的round返回值为double

select round(0.0068 ,4) from dual; --0.0068

再计算乘法的结果,double和bigint相计算的时候也是会发生隐式转化的

select 0.0066*100 from dual;--0.66select 0.0067*100 from dual;--0.67select 0.0068*100 from dual;--0.6799999999999999select 0.0069*100 from dual;--0.69

对于操作符号的运算,string,bigint和double都可以参与算术运算,string类型会转成double类型计算 当bigint和bigint进行除法运算的时候结果会返回double类型,当bigint和double共同计算的时候,big今天会转成doule类型,并且返回结果为double类型,

那么100变成了double类型,这时候问题就有点眉目了

select cast(0.0068 as double) from dual;--0.0068select cast(100 as double) from dual;--100.0select 0.0068*100.0 from dual;--0.6799999999999999

double浮点数运算的时候会有丢失精度的问题,这个是所有的浮点数运算的通病,我们可以再java下验证一下

public class TestDouble {    public static void main(String args[]){        Double a=0.0068;        Double b=100.0;        System.out.println(a*b);//0.6799999999999999        Double c=0.0067;        Double d=100.0;        System.out.println(c*d);//0.67        BigDecimal e= new BigDecimal(0.0068);        BigDecimal f=new BigDecimal(100.0);        System.out.println(e.multiply(f));//0.679999999999999962113639284666533058043569326400756835937500        BigDecimal g= new BigDecimal(Double.toString(0.0068));        BigDecimal h=new BigDecimal(Double.toString(100.0));        System.out.println(g.multiply(h));//0.68000    }}

当然这个问题的最终解决方案很简单,不过以后再计算对精度要求比较高的数据的时候建议还是设计成decimal类型

select round(10230*100/1497409,4) from  dual;


文章转载自wangming


更多问题欢迎加入MaxCompute钉钉群讨论
42559c7dde62e4d333c90e02efdf416257a4be27

原文链接:
http://click.aliyun.com/m/14019/
0 0
原创粉丝点击