FLOOR(3) 怎么可能等于 2?

Iai*_*der 4 sql-server

我试图找到一个可靠、有效的表达式来计算写一个正整数需要多少个十进制数字。

在数学上,整数中的十进制位数n1 + floor(log(n)),其中 log 是常用对数(以 10 为底)。

有多种使用内置函数构造等效表达式的方法,但其中一些会给出错误的结果。有人可以解释为什么吗?

这是一个例子。

如何计算日志?

计算常用对数的最简单方法是使用LOG10函数。

如果您希望所有对数都使用一个函数,则可以使用该LOG函数并使用第二个参数指定以 10 为底的函数。

在 2012 年之前,SQL Server 的LOG函数将仅计算自然对数(基数 e=2.71828...)。您可以通过将数字的自然对数除以数字的自然对数来计算对数到数字的任意底数。

以下查询为一些示例值计算所有三个表达式:

SELECT
  Number,
  LOG(Number, 10) AS LogAB,
  LOG10(Number) AS LogTen,
  LOG(Number) / LOG(10) AS LogOverLog
FROM (
  VALUES (999), (1000), (1001)
) AS Tally (Number);
Run Code Online (Sandbox Code Playgroud)

输出:

Number      LogAB                  LogTen                 LogOverLog
----------- ---------------------- ---------------------- ----------------------
999         2.99956548822598       2.99956548822598       2.99956548822598
1000        3                      3                      3
1001        3.00043407747932       3.00043407747932       3.00043407747932
Run Code Online (Sandbox Code Playgroud)

我选择了值 999、1000 和 1001,因为 1000 是数字数量增加的点。999有3位数字,1000有4位数字。

所有三个表达式的值明显相同,并且看起来是正确的。

让我们继续到地板步骤。

如何计算楼层?

您可以使用如下查询来查看上一个示例中的每个日志:

SELECT
  Number,
  FLOOR(LOG(Number, 10)) AS FloorLogAB,
  FLOOR(LOG10(Number)) AS FloorLogTen,
  FLOOR(LOG(Number) / LOG(10)) AS FloorLogOverLog
FROM (
  VALUES (999), (1000), (1001)
) AS Tally (Number);
Run Code Online (Sandbox Code Playgroud)

输出:

Number      FloorLogAB             FloorLogTen            FloorLogOverLog
----------- ---------------------- ---------------------- ----------------------
999         2                      2                      2
1000        2                      3                      2
1001        3                      3                      3
Run Code Online (Sandbox Code Playgroud)

999 和 1001 的每个表达式的值相等且正确。如果我们给每个值加 1,我们将在 999 中计数 3 位,在 1001 中计数为 4 位。

1000 的值不一样!如果我们给每个值加 1,如果我们使用该LOG10函数,我们将在 1000 中计数为 4 位,如果我们LOG以任何形式使用该函数,则计数为 3 位。

这里有矛盾!

FLOOR(3) 怎么可能等于 2?

含义很清楚:使用该LOG函数会给我一些值的错误计数,所以我应该使用该LOG10函数。

但是每个日志表达式本身的值都是相同且正确的。为什么 floor 函数会根据其输入产生不同的值?

Mar*_*ith 6

SELECT
  Number,
  CAST(LOG(Number, 10) AS VARBINARY) AS LogAB,
  CAST(LOG10(Number) AS VARBINARY) AS LogTen,
  CAST(LOG(Number) / LOG(10) AS VARBINARY) AS LogOverLog
FROM (
  VALUES (1000)
) AS Tally (Number);
Run Code Online (Sandbox Code Playgroud)

退货

Number      LogAB                   LogTen                  LogOverLog
----------- ----------------------- ----------------------- ----------------------
1000        0x4007FFFFFFFFFFFF      0x4008000000000000      0x4007FFFFFFFFFFFF
Run Code Online (Sandbox Code Playgroud)

0x4008000000000000正好3

0x4007FFFFFFFFFFFF2.99999999999999955591079014994

如果您正在寻找一个有效的表达式,那么CASE具有 10 种不同情况的表达式实际上会比计算对数消耗更少的 CPU(或者可能您可以使用嵌套的 case 表达式来进行三元搜索)