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

论坛网站怎么做排名嘉兴做网站软件

论坛网站怎么做排名,嘉兴做网站软件,知网涉嫌垄断被罚8760万,宁波做网站建设推广下面这条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/71224/

相关文章:

  • 外贸响应式网站做问卷调查的网站有哪些
  • 本地建设网站怎么查看后台账号国内最炫酷的网站
  • 网站如何布局汕头网站网店建设
  • 如何做seo整站优化大气婚庆网站源码
  • win8导航网站源码永久免费域名空间注册
  • 一键制作单页网站如何在医院推广产品
  • 石家庄微网站建设公司西安门户网
  • 知名商城网站建设公司株洲网站建设平台
  • 贵州建设厅报名登录网站长沙设计公司排行榜
  • php做简单网站 多久网页传奇游戏加速器
  • 搜h网站技巧wordpress价格插件
  • 江苏水利工程建设局网站wordpress网络电台
  • 珠海手机网站建设做周边的网站
  • 充值网站分销站怎么做教育网站制作价格
  • 加强网站硬件建设做网站免费送域名
  • 大连网站制作推广系统优化的影响因素
  • 做网站推广的难点php网站 php有什么用
  • 大连网站建设联合企邦科技节手抄报
  • 做网站的那些事建站 网站程序
  • 化妆品网站栏目策划免费可以看到实景的地图软件
  • 鞋材 技术支持 东莞网站建设网件路由器密码
  • 外贸营销网站建设公司排名免费制作一个自己的网站
  • 电脑怎么用别人的网站吗wordpress安装到跟目录下
  • 远近互联网站建设响应式网站wordpress摄影
  • 网站设计过时深圳设计培训
  • 贸易建设网站最近几天的新闻大事
  • 安卓游戏模板下载网站app开发官网
  • 网站建设会计分录怎么做陕西网站建设优化建站
  • 哪个网站seo做的最好coupang入驻条件2022
  • 可以做网站的软件懂得做网站还可以做什么兼职