TRUNC 结果为 0 位小数的错误值
TRUNC results wrong value for 0 decimals
我搜索以下情况时没有找到答案。我有一个简单的值要四舍五入到 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 等,
因此,ORACLE TRUNC FUNCTION 的结果应用于与 1/3*X 相乘的小数时是正确的,其中 X 不能被 3 完全整除。
查询和输出都没有问题。这是您的 client,它是您第一个查询输出中值的四舍五入。
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 数据类型 的 scale 有限制,您可以达到 100% 的准确性。这个限制是 38 位数字,post,你不可能有 100% 的准确性。您需要了解 mantissa 和 exponent。在这种情况下,scale 限制了 exponent 的可能最小值。
更新 OP 更新了问题。
select TRUNC(1 / 3 * 15, 0) WRONG from dual;
--5 is correct
与Oracle无关。它是纯数学。 15
可以被 3
整除,因此你得到一个 整数 5
作为结果。
Is 19608 a magic number ?
19608
不能完全整除 3
,你将得到 小数部分。我已经在上面展示了。 (1/3)*19608
的正确结果是 NOT 6536
。正确的结果是 6535.9
, 循环小数 。它永远不能被 3 整除。
更新 2 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
上述similar(not same)操作的查询结果不同的原因是Oracle从左到右求值。
当您执行 1/3*n
时,Oracle 对它的评估不同于 n/3
。在前一种情况下,首先评估 1/3
,从而创建 recurring non-terminating decimal number 0.3333....
,其中 3
是重复数字。现在,当你将它与一个 3
的倍数相乘时,它已经失去了 精度 ,因此最终结果也将是循环不终止数。
当你把它放在大括号内时,你是在要求 Oracle 显式计算大括号内的部分,而不仅仅是从左到右。因此,以下两个在 Oracle 中未计算:
1 / 3 * 15003
的评估方式与
不同
15003/3
我搜索以下情况时没有找到答案。我有一个简单的值要四舍五入到 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 等,
因此,ORACLE TRUNC FUNCTION 的结果应用于与 1/3*X 相乘的小数时是正确的,其中 X 不能被 3 完全整除。
查询和输出都没有问题。这是您的 client,它是您第一个查询输出中值的四舍五入。
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 数据类型 的 scale 有限制,您可以达到 100% 的准确性。这个限制是 38 位数字,post,你不可能有 100% 的准确性。您需要了解 mantissa 和 exponent。在这种情况下,scale 限制了 exponent 的可能最小值。
更新 OP 更新了问题。
select TRUNC(1 / 3 * 15, 0) WRONG from dual; --5 is correct
与Oracle无关。它是纯数学。 15
可以被 3
整除,因此你得到一个 整数 5
作为结果。
Is 19608 a magic number ?
19608
不能完全整除 3
,你将得到 小数部分。我已经在上面展示了。 (1/3)*19608
的正确结果是 NOT 6536
。正确的结果是 6535.9
, 循环小数 。它永远不能被 3 整除。
更新 2 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
上述similar(not same)操作的查询结果不同的原因是Oracle从左到右求值。
当您执行 1/3*n
时,Oracle 对它的评估不同于 n/3
。在前一种情况下,首先评估 1/3
,从而创建 recurring non-terminating decimal number 0.3333....
,其中 3
是重复数字。现在,当你将它与一个 3
的倍数相乘时,它已经失去了 精度 ,因此最终结果也将是循环不终止数。
当你把它放在大括号内时,你是在要求 Oracle 显式计算大括号内的部分,而不仅仅是从左到右。因此,以下两个在 Oracle 中未计算:
1 / 3 * 15003
的评估方式与
不同15003/3