当前位置: 首页 > news >正文

网站建设的开发方式长春建设工程信息网站

网站建设的开发方式,长春建设工程信息网站,哪里有做家教网站的,做模板网站的利与弊下面这条sql在oracle和POSTGRESQL/OPENGAUSS中的查询结果不一致 select cast(cast(0.5 as float) as integer);在oracle中返回1,在openGauss中返回0,咋一看好像是openGauss中使用了截断的方式,但是如果执行 select cast(cast(1.5 as float) as integ…

下面这条sql在oracle和POSTGRESQL/OPENGAUSS中的查询结果不一致

select  cast(cast(0.5 as float) as integer);

在oracle中返回1,在openGauss中返回0,咋一看好像是openGauss中使用了截断的方式,但是如果执行

select  cast(cast(1.5 as float) as integer);

则会发现oracle和openGauss中同样返回了2,这个时候就会猜想是不是这个float类型在两个数据库中实现并不一样导致的,因为ORACLE的float是按number格式存储的,不是标准定义中的浮点类型,而是一种精确类型;而openGauss中的float符合标准定义的浮点类型,是一种非精确类型。
但我们并不能妄下这种判断,多测几组数据:

select cast(cast(0.5 as float) as integer) c1 ,cast(cast(0.6 as float) as integer) c2 ,cast(cast(1.5 as float) as integer) c3,cast(cast(2.5 as float) as integer) c4,cast(cast(3.5 as float) as integer) c5, cast(cast(4.5 as float) as integer) c6
c1c2c3c4c5c6
012244

从这组数据中发现一个规律,当小数尾数为5进行舍入时,前一位总是偶数,这自然联想到了另一种四舍五入算法,即银行家算法,对应ORACLE12C新增的一个函数round_ties_to_even。

openGauss数据库是开源的,我们完全可以通过查看源码来验证我们的猜想。

接下来开始就是说明如何通过这种问题来找到对应的源码逻辑。

首先要知道一些openGauss的元数据基础知识。
openGauss的元数据基本继承postgresql,所以这个知识可以复用。
在postgresql中,几乎所有的类型、函数、操作符、规则等,都可以在元数据表中查到。对于类型转换,即cast,也有一张对应的表,即pg_cast,下面这个SQL就是查询从float8到int8是否存在直接的类型转换规则

select * from pg_cast h 
where h.castsource ='float8'::regtype 
and h.casttarget ='int8'::regtype;
castsourcecasttargetcastfunccastcontextcastmethodcastowner
70120483if

查到了是有的,这里castmethod为f,表示这个转换是使用某个函数进行转换的,一般是二进制存储结构有变更才会需要使用到函数。然后castfunc即为这个转换函数的oid,接下来我们去查这是用的哪个函数

select proname,prosrc from pg_proc where oid=483;
pronameprosrc
int8dtoi8

可以看到使用的是int8函数,然后int8的函数源码是dtoi8,此时我们就可以去openGauss源码中搜索dtoi8了,
找到了
.\openGauss-server\src\common\backend\utils\adt\int8.cpp

/* dtoi8()* Convert float8 to 8-byte integer.*/
Datum dtoi8(PG_FUNCTION_ARGS)
{float8 num = PG_GETARG_FLOAT8(0);/** Get rid of any fractional part in the input.  This is so we don't fail* on just-out-of-range values that would round into range.  Note* assumption that rint() will pass through a NaN or Inf unchanged.*/num = rint(num);/** Range check.  We must be careful here that the boundary values are* expressed exactly in the float domain.  We expect PG_INT64_MIN  to be an* exact power of 2, so it will be represented exactly; but PG_INT64_MAX* isn't, and might get rounded off, so avoid using it.*/if (num < (float8)PG_INT64_MIN || num >= -((float8)PG_INT64_MIN) || isnan(num)) {if (fcinfo->can_ignore && !isnan(num)) {ereport(WARNING, (errmsg("bigint out of range")));PG_RETURN_INT64(num < (float8)PG_INT64_MIN ? LONG_MIN : LONG_MAX);}ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("bigint out of range")));}PG_RETURN_INT64((int64)num);
}

这段代码注释加警告比实际逻辑还多,但真正要看的只有 num = rint(num);这一行,这里又引用到了rint函数,点进去

double rint(double x)
{return (x >= 0.0) ? floor(x + 0.5) : ceil(x - 0.5);
}

如果不是开发人员,对这种计算看不懂,可以借助AI

这段代码定义了一个名为 rint 的函数,用于将一个双精度浮点数 x 四舍五入到最接近的整数。具体来说:
如果 x 大于或等于 0.0,则返回 floor(x + 0.5),即将 x 加上 0.5 后向下取整。
如果 x 小于 0.0,则返回 ceil(x - 0.5),即将 x 减去 0.5 后向上取整。
这样可以实现对正数和负数的四舍五入。

这样就否定了之前的猜想,这里是按照常规的算法进行四舍五入的,但结果竟然和银行家算法一样。
于是我们回到最初的猜想,这个问题仍然与不精确的浮点类型有关,其实ORACLE也有这种浮点类型,叫binary_float和binary_double,这两个类型不能在sql中使用,只能在plsql中使用,我们写个简单的例子在ORACLE进行测试

declare
x binary_integer;
begin
select  cast(0.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(0.6 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(1.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(2.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(3.5 as binary_double) into x from dual;
dbms_output.put_line(x);
end;

0
0
1
2
3

竟然出现了第三种结果,即全部都是按trunc

再把binary_integer改成integer,再在ORACLE中测试

declare
x integer;
begin
select  cast(0.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(0.6 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(1.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(2.5 as binary_double) into x from dual;
dbms_output.put_line(x);
select  cast(3.5 as binary_double) into x from dual;
dbms_output.put_line(x);
end;

.5
.59999999999999998
1.5
2.5
3.5

出现了第四种结果!ORACLE的integer竟然能显示出小数!

我们理解不同的数据类型可以有不同的表现行为,也知道oracle中的integer其实是按number类型进行的实现,但是这明晃晃的声明了integer类型竟然还能打印出小数,这对于应用开发者来说如何能够接受?
当然,我们可以认为这个用例的用法是不合理的,正常情况下小数转换成整数应该使用函数来处理,而不是通过类型转换。也可能之前从来没有人这么用过,所以ORACLE一直没发现存在这个问题。

于是回到最开始的问题上,openGauss/postgresql和ORACLE表现不一致,究竟谁是对的,或许我们永远都无法找到准确答案,这只能算是一种行为差异,并且都可以解释得通。但在看到ORACLE换个方式出现了第三种结果,甚至还出现了整数类型显示小数这种奇葩BUG时,ORACLE的权威性陡然下降。

为了避免这种问题,建议无论在用什么数据库时,对于类型转换,还是慎重一些为好

  • 本文作者: DarkAthena
  • 本文链接: https://www.darkathena.top/archives/opengauss-float2int-cast-round
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处
http://www.yayakq.cn/news/875726/

相关文章:

  • 重庆网站推广外包企业广州市公司网站建设报价
  • 做网站需要的素材照片新闻式软文
  • 如何用文档做网站公众号文章模板素材
  • 济南正规网站建设公司怎么做网站才能吸引人
  • 网站可以几个服务器网站的seo怎么做
  • 网站开发成本网站建设费应怎样做会计分录
  • 如何免费自己创建网站环球军事新闻
  • 深圳网站制作招聘品牌网鞋有哪些牌子
  • 设计装修网站大全青岛西海岸新区建设网站
  • 房地产活动策划网站文章网站哪里建设好
  • 郑州网站制作计划js做网站好吗
  • php网站开发核心技术如何制作一个网站做淘宝券
  • 怎么做单位网站网站建设人力资源分配
  • 手机能建设网站忙四川建设厅住房和城乡建设厅
  • 海外网站如何做用户实名认证网站建设文字2000字
  • 四川网站建设方案购物网站优惠券怎么做
  • 建设校园网站必要性logo设计公司介绍
  • 厦门营销型网站建设公司用wordpress
  • 北京免费做网站广西网站开发建设
  • 网站建设与运营公司财务预算郑州网站建设与设计
  • 最好的网站建设网站数据库访问
  • 衡水营销网站建设如何查看网站页面大小
  • 常德红网官网网站河南网站优化要多少钱
  • 免费网站分析seo报告是坑吗做网站一班需要多少钱
  • 云南省网站开发软件自建网站做外贸谷歌推广
  • ppt模板下载的网站网站设置路由器
  • dede 获取网站标题做医疗设备的网站
  • 91大神网站建设公众号微信
  • 做网站怎么接广告赚钱吗做淘宝客进哪个网站
  • 网站在排版有哪些方法wordpress文章内图片不显示不出来