TRUNC结果错误的0小数值

时间:2015-07-03 11:28:49

标签: 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.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

在上面的SQL中你可以查看结果;确切地说,在500行之后,oracle的行为与可被3整除的数字不同。 如果以下答案为真,则表示15000完全可被3整除,15003 完全可被3整除。

我希望这有点意义,这与任何数学无关。

更新3

一个简单直接的问题可以如下:

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

                               TRUNC(1/3*15000,50)
--------------------------------------------------
                                              5000

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

                               TRUNC(1/3*15003,50)
--------------------------------------------------
         5000.999999999999999999999999999999999999

为什么我的oracle客户端(11.2.0.1.0)和服务器(11g 11.2.0.4.0-64bit)对可被3整除的数字的相同操作给出不同的结果?

最后更新 - 接受的答案

@ Lalit Kumar B感谢您对重复的十进制数字施加压力。 我遇到的情况不是oracle的错。 trunc正在正常工作。 问题是0.3333 ....分数乘以可被3整除但不完全的数字。这些数字的例子很少是300,15003等,

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

1 个答案:

答案 0 :(得分:4)

查询没有问题,输出也没有问题。它是 客户端 ,它会在您的第一个查询输出中对该值进行四舍五入。

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中, NUMBER数据类型比例限制为100%准确度。而且这个限制是38位数,你不能100%准确。您需要了解尾数指数。在这种情况下,比例会对指数的可能最小值设置限制。

更新 OP更新了问题。

  

从双选择TRUNC(1/3 * 15,0)WRONG;   --5是正确的

与Oracle无关。这是纯粹的数学15完全可以归3,因此您会得到整数 5

  

19608是一个神奇的数字吗?

{p> 19608 <{1}}
完全可分割小数部分。我已经在上面展示了。 3的正确结果是 (1/3)*19608。正确的结果是6536 重复小数。它永远不会被3整除。

更新2 OP更新了问题。

6535.9

上述查询类似不相同)操作的结果不同的原因是Oracle从左到右进行评估。

执行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的方式对其进行评估。在前一种情况下,首先评估n/3,从而创建 recurring non-terminating decimal number 1/3,其中0.3333....是重复数字。现在,当您将其乘以3的倍数时,它已经丢失了精度,因此最终结果也将是重复的非终止数字。

当你把它放在大括号内时,你要求Oracle明确评估大括号内的部分,而不是从左到右。因此,在Oracle中,以下两个未评估的方式相同

3

的评估方式与

的评估方式不同
1 / 3 * 15003