在SQL中逼近e的代码示例

70 阅读1分钟

如果你是在PostgreSQL上运行,你可以试试下面这个很酷的查询:

WITH RECURSIVE
  r (r, i) AS (
    SELECT random(), i 
    FROM generate_series(1, 1000000) AS t (i)
  ),
  s (ri, s, i) AS (
    SELECT i, r, i
    FROM r
    UNION ALL
    SELECT s.ri, r.r + s.s, s.i + 1
    FROM r
    JOIN s ON r.i = s.i + 1
    WHERE r.r + s.s <= 1
  ),
  n (n) AS (
    SELECT max(i) - min(i) + 2
    FROM s
    GROUP BY ri
  )
SELECT avg(n)
FROM n

它打印的是什么(经过一段时间)?它打印的是e (几乎是)。这里有一些示例结果:

2.7169115477960698
2.7164145522690296
2.7172065451410937
2.7170815462660836

不完美,当然,这里有一个用SQL写的更好的近似值:

SELECT exp(1);

产生的:

2.718281828459045

足够接近......它是如何工作的?这是一个很酷的近似值,已经被描述过很多次了,例如这里。在散文中。

平均来说,它在0和1之间取e个随机值,直到这些值的总和超过1。

再看一下这个查询:

WITH RECURSIVE
  -- "random values between 0 and 1"
  r (r, i) AS (
    SELECT random(), i 
    FROM generate_series(1, 1000000) AS t (i)
  ),
  s (ri, s, i) AS (
    SELECT i, r, i
    FROM r
    UNION ALL
    SELECT s.ri, r.r + s.s, s.i + 1
    FROM r
    JOIN s ON r.i = s.i + 1
    -- "... until the sum exceeds 1"
    WHERE r.r + s.s <= 1
  ),
  -- "number of values taken until ..."
  n (n) AS (
    SELECT max(i) - min(i) + 2
    FROM s
    GROUP BY ri
  )
-- "on average"
SELECT avg(n)
FROM n