Sql TRUNC结果0位小数的值错误

Sql TRUNC结果0位小数的值错误,sql,oracle,math,numbers,Sql,Oracle,Math,Numbers,当我搜索下面的情况时,我没有找到答案。我有一个简单的值,可以四舍五入到0位小数。我在oracle中尝试以下查询,得到如下结果: select 1 / 3 * 19608 CORRECT from dual; --6536 is correct select TRUNC(1 / 3 * 19608, 0) WRONG from dual; --6535 which is wrong select TRUNC(1 / 3 * 19608, 2) WRONG from dual; --6535

当我搜索下面的情况时,我没有找到答案。我有一个简单的值,可以四舍五入到0位小数。我在oracle中尝试以下查询,得到如下结果:

select 1 / 3 * 19608 CORRECT from dual;
--6536 is correct

select TRUNC(1 / 3 * 19608, 0) WRONG from dual;
 --6535 which is wrong

select TRUNC(1 / 3 * 19608, 2) WRONG from dual;
 --6535.99 which is wrong
如果您有与此情况相关的问题,请告诉我


更新

很抱歉拒绝你的回答。我发现还有一个问题,您的答案仍然无效:

select TRUNC(1 / 3 * 15, 0) WRONG from dual;
--5 is correct
对于小数字,我得到了正确的数字。我也希望给出错误的结果,因为19608年的结果是错误的。19608是一个神奇的数字吗


更新2

我理解下面答案中解释的数学。但我仍然对oracle TRUNC函数表示怀疑,因为它没有提供预期的正确输出。现在,我想用下面的一个例子来说明这一点:

SELECT ( (4500 + ROWNUM) * 3) multiple_3,
       TRUNC (1 / 3 * ( (4500 + ROWNUM) * 3), 2) result_with_trunc,
       1 / 3 * ( (4500 + ROWNUM) * 3) no_trunc
  FROM DUAL CONNECT BY 4500 + ROWNUM < 6000
为什么我的oracle客户端(11.2.0.1.0)和服务器(11g 11.2.0.4.0-64位)对一个可被3整除的数字执行相同操作时会给出不同的结果


上次更新-接受的答案

@感谢您对反复出现的十进制数字的关注。 我遇到的这个案例不是oracle的错。trunc正在正确地执行其工作。 问题是0.3333。。。。分数乘以可被3整除但不能完全整除的数。这类数字的例子很少有300、15003等


因此,当将ORACLE TRUNC函数的结果应用于与1/3*X相乘得到的分数时,结果是正确的,其中X不能完全被3整除。

查询和输出都没有问题。是您的客户机对第一个查询的输出值进行四舍五入

SQL> SELECT TRUNC(1 / 3 * 19608, 50) FROM dual;

TRUNC(1/3*19608,50)
-------------------
               6536

SQL> set numwidth 50
SQL> SELECT TRUNC(1 / 3 * 19608, 50) FROM dual;

                               TRUNC(1/3*19608,50)
--------------------------------------------------
         6535.999999999999999999999999999999999999

SQL>
在我的SQL*Plus客户端中,我调整了numwidth,您可以看到实际值

此外,在Oracle中,数字数据类型的比例有限,您可以100%准确。这个限制是38位,你不能100%准确。你需要理解尾数和指数。在这种情况下,标度指数的可能最小值进行限制

更新OP更新了问题

SQL> set numwidth 50
SQL> SELECT (1/3)*5000*3 FROM dual;

                                      (1/3)*5000*3
--------------------------------------------------
         5000.000000000000000000000000000000000001

SQL> SELECT (1/3)*(5000*3) FROM dual;

                                    (1/3)*(5000*3)
--------------------------------------------------
                                              5000

SQL> SELECT trunc((1/3)*(5000*3),2) FROM dual;

                           TRUNC((1/3)*(5000*3),2)
--------------------------------------------------
                                              5000

SQL> SELECT 1 / 3 * 15003 FROM dual;

                                         1/3*15003
--------------------------------------------------
         5000.999999999999999999999999999999999999

SQL> SELECT 15003/3 FROM dual;

                                           15003/3
--------------------------------------------------
                                              5001
从双精度中选择TRUNC(1/3*15,0)错误; --5是正确的

这与甲骨文无关。它是纯粹的数学
15可以被
3
完全整除,因此得到一个整数

19608是一个神奇的数字吗

19608
不能被
3
完全整除,您将拥有小数部分。我已经在上面展示了。
(1/3)*19608的正确结果是不是
6536
。正确的结果是带有循环小数的
6535.9
。它永远不会被3整除

更新2OP更新了问题

SQL> set numwidth 50
SQL> SELECT (1/3)*5000*3 FROM dual;

                                      (1/3)*5000*3
--------------------------------------------------
         5000.000000000000000000000000000000000001

SQL> SELECT (1/3)*(5000*3) FROM dual;

                                    (1/3)*(5000*3)
--------------------------------------------------
                                              5000

SQL> SELECT trunc((1/3)*(5000*3),2) FROM dual;

                           TRUNC((1/3)*(5000*3),2)
--------------------------------------------------
                                              5000

SQL> SELECT 1 / 3 * 15003 FROM dual;

                                         1/3*15003
--------------------------------------------------
         5000.999999999999999999999999999999999999

SQL> SELECT 15003/3 FROM dual;

                                           15003/3
--------------------------------------------------
                                              5001
上述查询中类似(不相同)操作的结果不同的原因是Oracle从左到右求值

当您执行
1/3*n
时,Oracle对它的评估与
n/3
不同。在前一种情况下,首先计算
1/3
,从而创建
0.3333….
,其中
3
是循环数字。现在,当您将其与一个是
3
倍数的数字相乘时,它已经失去了精度,因此最终结果也将是重复出现的非终止数字

当您将它放在大括号内时,您要求Oracle显式地计算大括号内的部分,而不仅仅是从左到右。因此,以下两项在Oracle中的评估方式不同:

1 / 3 * 15003
其评估方法与

15003/3

应该是0吗?1/3=0和0*19608=0…不。它给了我预期的结果,但只是少了一个值。甲骨文的数学能力远远不是像Matlab这样的专用软件。由于1/3是周期性的(以10为基数和以2为基数),您需要重写逻辑,因此它的任何步骤都不需要无限浮点存储。@lvaroG.Vicario:谢谢。你的解决方案有效。我把它做成TRUNC(19608*1/3,0),它给出了正确的结果。但是你能不能在不改变逻辑的情况下提出一些建议来获得正确的值。关键是Oracle不理解分数,所以它只能从左到右计算,并且在
1/3
时会失去精度。执行
19608/3
很好,因为它有整数解。另一个解决方案是舍入而不是截断。什么更好,基本上取决于你的确切需求。谢谢你的解释。但我关心的是,为什么一个完全可除的数字3显示了错误的值。为什么考虑第一个数字而不是将第二个数字直接除以3。希望您能在不更改代码的情况下给出一些解决方案。@Abs大多数计算机程序都不是那么智能。由于
*
/
具有相同的优先级,Oracle从左到右计算:
1/3*19608
=
0.33333…*19608
。不再是整数!Oracle不知道他是否可以将表达式重写为
19608/3
@Lalit Kumar B,请参见上述更新。很抱歉拒绝您的回答。@lalit-kumar-b可能是因为很久以前我离开学校时忘记了数字。现在我又从1开始。谢谢你提醒我基本知识。我想请*你发布一些我在上面的解释中理解错误的数学基础知识。@A再次更新你的问题2。是你的客户在对数字进行舍入。最后一次,打开SQL*Plus,执行以下操作:
设置numwidth 50
,然后运行SQL。