2015-09-30 6 views
1

Мне нужно вычислить факториал переменной в Google BigQuery - есть ли функция для этого? Я не могу найти один в документации здесь:Факториал в Google BigQuery

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

Мой Предложенное решение в этой точке, чтобы вычислить факториал чисел от 1 до 100, и загрузить, что в качестве таблицы и присоединиться к этой таблице. Если у вас есть что-то получше, проконсультируйтесь.

Как контекст может показать лучшее решение, факториал используется в контексте вычисления вероятности Пуассона случайной величины (количество событий в окне времени). См. Первое уравнение здесь: https://en.wikipedia.org/wiki/Poisson_distribution

+0

вы можете легко использовать java script udf для этого - https://cloud.google.com/bigquery/user-defined-functions. –

+1

До 100! будет сложной задачей. BigQUery использует 64-битное целое число, которое до 20! но 21! уже не подходит. –

+0

Иногда люди используют факториалы как строительный блок для чего-то еще, что не взрывается так быстро, как факториалы, такие как вычисления (n выбирают k) для малых k. Если вы делаете что-то подобное, добавьте к вопросу, так как вы можете получить лучшее решение таким образом. – eubrandt

ответ

0

Продление ответа Михаила быть общими и правильными для вычисления факториала для всего числа от 1 до п, где п < 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())}); 
}" 
) 
+0

Но теперь попробуйте n = 500. (Javascript-поплавки IEEE double, поэтому они достигают примерно 2^1024. 500! Составляет около 2^3767.) – eubrandt

4

Попробуйте ниже. Быстрый & грязного примера

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}); 
}" 
) 
+0

Закрыть! Теперь подключите 25 к 12 в вашем примере, и вы увидите, что он не работает. Также мы хотим вычислить это для всех чисел, и мы не хотим, чтобы все числа повторялись снова и снова. Используя свой код в качестве основы, у меня это работает. Как и прежде, я добавил его в качестве ответа - посмотрите, что вы думаете! – cgnorthcutt

+0

Я думаю, что это искусство, чтобы дать ответ таким образом, чтобы вы могли сделать несколько небольших шагов самостоятельно, чтобы заставить его работать именно для вашего дела. Я рад, что вы получили эту работу :) Тем не менее, выберите row_numbers ...не совсем общий - вы можете улучшить его, чтобы полностью исключить использование таблиц, все еще создавая столько чисел, сколько вам нужно. дайте мне знать, если вы хотите увидеть это –

+0

Обработка больших чисел на разных платформах может быть сложной задачей. Трюк - строка экспоненциальная, а затем назад к float. Конечно, это было бы поучительно! – cgnorthcutt

1

Если прямой подход работает для значений, вам нужно рассчитать распределение Пуассона, а затем остыть. Если вы достигнете точки, в которой она взрывается, или дает вам неточные результаты, то читайте для веселого времени численного анализа.

В целом вы получите лучший диапазон и численную стабильность, если вы выполните арифметику по логарифмам, а затем exp() в качестве конечной операции.

  1. Вы хотите: c^k/k! ехр (-с). (! С^к/к ехр (-с))
  2. Вычислить его журнал, пер,
    т.е. к п (х) - п (К!) - с
  3. Тейк ехр() этого.

Хорошо, но как мы получаем ln (k!) Без вычисления k !? Существует функция, называемая гамма-функцией, практическая точка которой заключается в том, что ее логарифм gammaln() может быть непосредственно аппроксимирован, а ln (k!) = Gammaln (k + 1).

В файле Phil Mainwaring answer here есть Javascript gammaln(), который я не тестировал, но при условии, что он работает, он должен вписаться в UDF для вас.