public QueueSysResult calculate(int m) {
        double p0 = 0.0;
        double rho = lambda / mu;

        double[] rho_pow = new double[N + 1];
        rho_pow[0] = 1.0;
        for (int i = 1; i < rho_pow.length; ++i) {
            rho_pow[i] = rho_pow[i - 1] * rho;
        }

        double[] m_pow = new double[N + 1 - m];
        m_pow[0] = 1.0;
        for (int i = 1; i < m_pow.length; ++i) {
            m_pow[i] = m_pow[i - 1] * m;
        }

        double[] sum_components = new double[N + 1];

        for (int i = 0; i <= m; ++i) {
            sum_components[i] = rho_pow[i] * factorialsQuotient(new int[] { N }, new int[] { i, N - i });
            p0 += sum_components[i];
        }
        for (int i = m + 1; i <= N; ++i) {
            sum_components[i] = rho_pow[i] / m_pow[i - m] * factorialsQuotient(new int[] { N }, new int[] { N - i, m });
            p0 += sum_components[i];
        }

        p0 = 1.0 / p0;

        double averageSystemCalls = 0.0;
        for (int i = 0; i < N; ++i) {
            averageSystemCalls += sum_components[i] * i;
        }
        averageSystemCalls *= p0;

        double averageSystemTime = averageSystemCalls / (lambda * (N - averageSystemCalls));
        double averageQueueTime = averageSystemTime - 1 / mu;
        double averageQueueCalls = 0.0;
        double averageOccupiedServicePoints = (N - averageSystemCalls) * rho;

        double value = c1 * m + c2 * averageSystemCalls;

        QueueSysResult result = new QueueSysResult(value, averageSystemCalls, averageQueueCalls, averageSystemTime, averageQueueTime, averageOccupiedServicePoints);
        cachedResults.put(m, result);

        return result;
    }