【问题标题】:Understanding behavior of remainder() function in Oracle了解 Oracle 中剩余()函数的行为
【发布时间】:2017-05-28 06:28:17
【问题描述】:

根据剩余(n2,n1) 函数 (https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions133.htm) 的 Oracle 文档,剩余(n2,n1) 函数的计算结果为 = n2 - n1 * N 其中 N = ROUND(n2/n1) 和 n1 ! = 0。

所以,我希望使用上面记录的计算余数的方法返回 -2,如下所示:

REMAINDER(10,4)
=10 - 4 * N where N = ROUND(10/4) 
=10 - 4 * 3 since ROUND(10/4) = 3 
=10 - 12
=-2

但是,在 Oracle 10g、11g 和 12c 中运行剩余 (10,4) 会返回 2 而不是 -2。

有人可以解释一下为什么没有按照 oracle 如何评估余数的记录方法评估余数(10,4)吗?

附加信息:每隔一个 n2 就会发生这种行为,其中 n2 是 n1 / 2 的倍数。可以通过运行以下 SQL 来验证,其中每个余数函数值应与其旁边的值匹配。但它只匹配 n2 的所有其他值。 运行 SQL:

select
remainder(2,4), 2-4*round(2/4),--OUTPUT:2, -2
remainder(6,4),6-4*round(6/4), --OUTPUT: -2, -2
remainder(10,4),10-4*round(10/4),--OUTPUT: 2, -2
remainder(14,4),14-4*round(14/4)--OUTPUT: -2, -2
from dual 

【问题讨论】:

  • 显然ROUND(2.5) 在直接调用时返回 3,但是在 REMAINDER 函数中进行的任何舍入都会导致 ROUND(2.5) 的结果为 2。您可能想查看 @987654327 @函数。
  • @BobJarvis - 不知道“显然”是什么意思。如果您从未与 Oracle 合作过,请让其他人发表意见。 Round(10/4) 在 Oracle 中是 3
  • 我每天都在使用 Oracle。虽然ROUND(2.5) 可能会返回 3(正如它所明确的那样),但请解释为什么REMAINDER(10,4) 是 2 而不是 -2。谢谢。

标签: oracle oracle11g oracle10g oracle12c


【解决方案1】:

编写文档的人(他们似乎不记得算术中的一些定义)他们自己似乎不确定他们写了什么。一方面,他们在解释的早期确实提到了ROUND - 但后来当他们给出更正式的定义时,他们说

•如果 n1 != 0,则余数为 n2 - (n1*N) 其中 N 是整数 最近的n2/n1

“最接近的整数”在算术中没有正式定义,实际上允许使用该名称来表示 round(x),除非 x 的小数部分正好是 0.5,在这种情况下“最接近的整数”是不明确的并且一可以选择使用“向下取整”作为他们自己对“最接近整数”的定义。

如果可以,请不要对文档中的这种不一致感到太沮丧。你会看到更多。

然而:更糟糕的是行为不一致。我使用 Oracle 12.1,在我的机器上我刚刚尝试过,我得到了

remainder(10, 4) =  2
remainder( 6, 4) = -2

没有韵律或理由。使用 FLOOR 等进行自己的划分要好得多。

编辑 - 或者有什么原因;也许他们使用“最接近整数”的定义来表示,在平局的情况下,最接近的偶数整数。仍然会产生意想不到的结果,最好不要使用 Oracle 的 REMAINDER() 函数。

【讨论】:

  • 查看了 ROUND() 文档 (docs.oracle.com/cd/B19306_01/server.102/b14200/…)。它提到对于 NUMBER 类型,ROUND() 总是从 0 开始舍入(从 11g 中省略)。所以 ROUND(2.5) = 3 在自行运行时符合预期。但是,看起来当 REMAINDER() 函数在内部使用 ROUND() 时,它可能会偏离此行为。当在 REMAINDER() 中调用 ROUND(N2/N1) 时会发生这种偏差,它将 N2/N1 转换为非数字类型(例如 BINARY_FLOAT)。如果为真,那么它会将 ROUND(10/4) 评估为偶数(到 2 而不是 3)。
  • @lazyPanda - 我非常怀疑 REMAINDER 的内部实现调用 ROUND 函数。我认为它以接近您的描述的方式直接计算它 - “最近的整数”,如果有疑问,是“最近的 even 整数”。这可能使用了一些基本的机器语言函数,而不是更高级别的 ROUND。
  • 当 n2/n1 等于 x.5 时,您认为它是最接近的偶数是正确的。在 11g 文档中发现:如果 n1 != 0,则余数为 n2 - (n1*N),其中 N 是最接近 n2/n1 的整数。 如果 n2/n1 等于 x.5,则 N 是最接近的偶数。不同版本的文档不一致。 ROUND() 函数在 10g 文档中有更多信息,而 REMAINDER() 函数在 11g 文档中有更多信息。
  • @lazyPanda 这是数学余数的奇怪定义;当然它应该是 n2 - (floor(n2/n1)*n1)?!当他们将其实现为最接近的偶数而不是下限时,他们在想什么?!
  • 或者实际上这甚至不是 Oracle 用于负数的(用于 MOD)。在 Oracle 中,MOD 的符号似乎与 n1 的符号相同——甚至不是唐·克努斯的“地板师”。如果我曾经在 Oracle 或几乎任何其他软件中做过算术(数论、整数算术),我会确保测试 MOD 并编写我自己的,如果它与数学定义不同,这很可能是这种情况我正在阅读的大多数软件。 (我当时在想exp(0, 0) = 1 将是我必须忍受的唯一烦人的事情!):-)
猜你喜欢
  • 2014-01-31
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
相关资源
最近更新 更多