Как я могу вычислить значения Erlang C на сервере SQL, если тип данных float слишком мал? - PullRequest
0 голосов
/ 20 июня 2020

Мы реализуем вычисление Erlang C в нашем центре обработки данных, и я наткнулся на препятствие: ошибки переполнения с типом данных SQL сервера float.

Как я могу представить значения, превышающие 10 ^ 308 на SQL сервере, таким образом, чтобы я мог выполнять арифметические операции c?

Статья в Википедии: Erlang C Лучшее объяснение Erlang C Расчет

Расчет Erlang C отвечает на вопрос: «Учитывая прогнозируемый объем вызовов и расчетное время обработки, сколько агентов мы должны запланировать, чтобы гарантировать Достаточная часть наших абонентов получает ответ в течение указанного времени? »

Например: наш уровень обслуживания составляет 75% вызовов, на которые необходимо ответить в течение 60 секунд. В приведенной ниже таблице показано укомплектование персоналом для различных объемов и времени обработки, которые имеют отношение к нашей деятельности.

Excel grid

You can see that when the required number of agents passes about 140, SQL Server can no longer handle the size of number required.

The issue here is the exponentiation and factorial terms in the middle of the formula.
] 2 Например, расчет, который приводит к первой ошибке, имеет V = 425 и AHT = 600: (425 звонков / 30 м @ 10 м / звонок -> 141 звонков в час -> 141 эрланг) A = 141 начальная оценка при n = 142

Для N = 142 A ^ N равно 3.02002e + 305 и N! это 2.69536e + 245. Завершение расчета дает около 6% уровня обслуживания, что недостаточно. Для N = 143 A ^ N равно 4,27836e + 307 и N! это 3.85437e + 247. Завершение расчета дает около 24% уровня обслуживания, что все еще недостаточно. Для N = 144 A ^ N равно 6.06101e + 309 и SQL Сервер выдает ошибку, когда я пытаюсь его вычислить, поскольку тип float может обрабатывать числа только до 1e308.

edit:

@ chtz и @dmuir дали нужную мне подсказку. Вместо того, чтобы накапливать A ^ i и i! по отдельности, я накапливаю их вместе, как было предложено, и новая версия работает безупречно.

SELECT 
    @acc_ai_if = @acc_ai_if * @intensity / cast(@agentcount as float)
--  @acc_if = @acc_if * @agentcount
--, @acc_ai = @acc_ai * @intensity  -- this overflows for N>143
;

1 Ответ

1 голос
/ 20 июня 2020

К сожалению, я ничего не знаю о сервере SQL, но вот алгоритм, который избегает больших чисел, и программа C для его демонстрации.

Ключ, как отмечает chtz в их комментарии, заключается в том, чтобы избежать вычисления больших степеней и больших факториалов. Вводя произвольные имена, пусть

a(N) = pow( A, N)/factorial(N)
b(N) = Sum{ 0<=i<N | a(i)}

Затем мы можем записать вероятность для N> A как

P = N/(N-A) * a(N) / (b(N) + N/(N-A) * a(N))

Обратите внимание, что у нас есть

b(N+1) = b(N) + a(N)
a(N+1) = (A/(N+1))*a(N)

чтобы мы могли приступить к написанию кода на основе этих рекурсий. Но и a, и b становятся большими с увеличением N, поэтому я думаю, что лучше ввести еще одну функцию как

beta( N) = a(N)/b(N)

Тогда beta (1) = A, а beta (N) уменьшается (до нуля) когда N превышает значение A. В терминах бета-версии мы имеем

P = N/(N-A) * beta(N) / (1 + N/(N-A) * beta(N))

Небольшая алгебра дает эту рекурсию для бета-версии:

beta(N) = (A/N) * beta(N-1)/(1+beta(N-1))

и, как отмечалось выше,

beta(1) = A

Вот программа C, основанная на этих идеях:

#include    <stdio.h>
#include    <stdlib.h>

    // compute beta(toN) from A and previous value of beta
    static  double  beta_step( int A, int toN, double beta)
    {
    double  f = A/(double)toN;
        return f*beta/(1.0+beta);
    }
    int main( void)
    {
    int A = 140;
    int np = 20;    // number of probabilities to compute
        // compute values for beta at N=1..A    
    double  beta = A;
        for( int N=2; N<=A; ++N)
        {   beta = beta_step( A, N, beta);
        }
        // compute probabilities at N=A+1..A+np
        for( int i=1; i<=np; ++i)
        {
        int N = A+i;
            beta = beta_step( A, N, beta);
        double  f = (double)N/(double)i;    // == N/(N-A)
        double  prob = f*beta/(f*beta + 1.0);   
            printf( "%d\t%f\n", N, prob);
        }   
        return EXIT_SUCCESS; 
    }

Я скомпилировал это (используя довольно старинный g cc (4.8.5)) с

gcc -o erl -std=gnu99 -Wall erl.c
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...