Google BigQuery 中的阶乘

Factorial in Google BigQuery

我需要在 Google BigQuery 中计算一个变量的阶乘 - 有这个函数吗?我在此处的文档中找不到:

https://cloud.google.com/bigquery/query-reference#arithmeticoperators

此时我提出的解决方案是计算数字 1 到 100 的阶乘并将其作为 table 上传并与 table 合并。如果大家有更好的,请指教

由于上下文可能会揭示最佳解决方案,因此阶乘用于计算随机变量的泊松概率(window 时间内的事件数)。在这里查看第一个等式:https://en.wikipedia.org/wiki/Poisson_distribution

在下面试试。快速和肮脏的例子

select number, factorial 
FROM js(
// input table
(select number from
(select 4 as number),
(select 6 as number),
(select 12 as number)
),
// input columns
number,
// output schema
"[{name: 'number', type: 'integer'},
{name: 'factorial', type: 'integer'}]",
// function
"function(r, emit){
  function fact(num)
  {
      if(num<0)
       return 0;
      var fact=1;
      for(var i=num;i>1;i--)
        fact*=i;
      return fact;
   }

  var factorial = fact(r.number)

  emit({number: r.number,  factorial: factorial});
}"
)

将 Mikhail 的答案扩展为通用且正确的计算所有数字 1 到 n 的阶乘,其中 n < 500,以下解决方案成立并且可以有效计算:

select number, factorial 
FROM js(
// input table
(
  SELECT
    ROW_NUMBER() OVER() AS number, 
    some_thing_from_the_table
  FROM
    [any table with at least LIMIT many entries]
  LIMIT
    100 #Change this to any number to compute factorials from 1 to this number
),
// input columns
number,
// output schema
"[{name: 'number', type: 'integer'},
{name: 'factorial', type: 'float'}]",
// function
"function(r, emit){
  function fact(num)
  {
      if(num<0)
       return 0;
      var fact=1;
      for(var i=num;i>1;i--)
        fact*=i;
      return fact;
   }

  #Use toExponential and parseFloat to handle large integers in both Javascript and BigQuery
  emit({number: r.number,  factorial: parseFloat(fact(r.number).toExponential())});
}"
)

如果直接方法适用于您需要计算泊松分布的值,那么很酷。如果你达到它爆炸的地步或给你不准确的结果,然后继续阅读数值分析的乐趣。

一般来说,如果您对对数进行算术运算,然后将 exp() 作为最终运算,您将获得更好的范围和数值稳定性。

  1. 你要:c^k/k!指数(-c)。
  2. 计算其对数,ln( c^k / k!exp(-c) ),
    即 k ln(x) - ln(k!) - c
  3. 取其中的 exp()。

但是我们如何在不计算 k! 的情况下得到 ln(k!)?有个函数叫gamma函数,这里的实用点是它的对数gammaln()可以直接近似,ln(k!) = gammaln(k+1).

Phil Mainwaring 的 answer here 中有一个 Javascript gammaln(),我还没有测试过,但假设它有效,它应该适合你的 UDF。

您最多可以获得 27 个!使用 SQL UDF。高于该值 NUMERIC 类型会出现溢出错误。

CREATE OR REPLACE FUNCTION factorial(integer_expr INT64) AS ( (
    SELECT
      ARRAY<numeric>[ 
      1,
      1,
      2,
      6,
      24,
      120,
      720,
      5040,
      40320,
      362880,
      3628800,
      39916800,
      479001600,
      6227020800,
      87178291200,
      1307674368000,
      20922789888000,
      355687428096000,
      6402373705728000,
      121645100408832000,
      2432902008176640000,
      51090942171709440000.,
      1124000727777607680000.,
      25852016738884976640000.,
      620448401733239439360000.,
      15511210043330985984000000.,
      403291461126605635584000000.,
      10888869450418352160768000000.][
    OFFSET
      (integer_expr)] AS val ) );

  select factorial(10);