Числа Бернулли представляют собой последовательность рациональных чисел, полезных для расширения ряда Тейлора, формулы Эйлера-Маклаурина и дзета-функции Римана.
Числа Бернулли используются при оценке некоторого увеличения. Математические функции, включая функции tgamma, lgamma и полигамма.
#include <boost/math/special_functions/bernoulli.hpp>
namespace boost { namespace math {
template <class T>
T bernoulli_b2n(const int n);
template <class T, class Policy>
T bernoulli_b2n(const int n, const Policy &pol);
}}
Оба возвращают (2*n)th Бернулли номер B2n.
Обратите внимание, что поскольку все нечетные числа Бернулли равны нулю (кроме B1, что равно -½), интерфейс возвращает только четные числа Бернулли.
Эта функция использует быстрый поиск таблиц для низкоиндексированных чисел Бернулли, в то время как большие значения рассчитываются по мере необходимости, а затем кэшируются. Механизм кэширования требует определенного количества кода безопасности потока, поэтому unchecked_bernoulli_b2n
может обеспечить лучший интерфейс для выполнения критического кода.
Конечный аргумент Политика является необязательным и может использоваться для контроля поведения функции: как она обрабатывает ошибки, какой уровень точности использовать и т. д.
См. Политика для более подробной информации.
Простой пример вычисляет значение B4, где тип возврата double
, обратите внимание, что аргумент bernoulli_b2n 2 не 4, поскольку он вычисляет B2N.
try
{
std::cout
<< std::setprecision(std::numeric_limits<double>::digits10)
<< boost::math::bernoulli_b2n<double>(2) << std::endl;
Так B4 == -1/30 == -0.03333333333333
Если мы используем Boost.Multiprecision и его 50-значную цифру типа плавающей точки cpp_dec_float_50
, мы можем вычислить значение гораздо больших чисел, таких как B200, а также получить гораздо более высокую точность.
std::cout
<< std::setprecision(std::numeric_limits<boost::multiprecision::cpp_dec_float_50>::digits10)
<< boost::math::bernoulli_b2n<boost::multiprecision::cpp_dec_float_50>(100) << std::endl;
-3.6470772645191354362138308865549944904868234686191e+215
#include <boost/math/special_functions/bernoulli.hpp>
template <>
struct max_bernoulli_b2n<T>;
template<class T>
inline T unchecked_bernoulli_b2n(unsigned n);
unchecked_bernoulli_b2n
предоставляет доступ к номерам Бернулли без каких-либо проверок на переполнение или недействительные параметры. Он реализован как прямой (и очень быстрый) поиск таблицы, и, хотя он не рекомендуется для общего использования, он может быть полезен во внутренних циклах, где требуется максимальная производительность, а проверка ошибок перемещается за пределы цикла.
Самое большое значение, которое вы можете передать unchecked_bernoulli_b2n<>
, это max_bernoulli_b2n<>::значение
: переход значений больше, чем это приведет к ошибке переполнения буфера, поэтому очевидно важно поместить обработку ошибок в свой собственный код при использовании этого прямого интерфейса.
Значение boost::max_bernoulli_b2n<T>::значение
варьируется в зависимости от типа T, для типов float
/longdoubledouble
Это самое большое значение, которое не переполняет целевой тип: например, boost::math::max_bernoulli_b2n<double>::value
составляет 129. Однако для многоточных типов это наибольшее значение, для которого результат может быть представлен как отношение двух 64-битных целых чисел, например boost::::max_bernoulli_b2n<boost::cpp_dec_float_50>::value
составляет всего 17. Конечно, более крупные индексы могут быть переданы bernoulli_b2n<T>(n)
, но затем вы теряете быстрый поиск таблицы (т.е. значения могут быть вычислены).
std::cout << "boost::math::max_bernoulli_b2n<float>::value = " << boost::math::max_bernoulli_b2n<float>::value << std::endl;
std::cout << "Maximum Bernoulli number using float is " << boost::math::bernoulli_b2n<float>( boost::math::max_bernoulli_b2n<float>::value) << std::endl;
std::cout << "boost::math::max_bernoulli_b2n<double>::value = " << boost::math::max_bernoulli_b2n<double>::value << std::endl;
std::cout << "Maximum Bernoulli number using double is " << boost::math::bernoulli_b2n<double>( boost::math::max_bernoulli_b2n<double>::value) << std::endl;
boost::math::max_bernoulli_b2n<float>::value = 32
Maximum Bernoulli number using float is -2.0938e+038
boost::math::max_bernoulli_b2n<double>::value = 129
Maximum Bernoulli number using double is 1.33528e+306
#include <boost/math/special_functions/bernoulli.hpp>
namespace boost { namespace math {
template <class T, class OutputIterator>
OutputIterator bernoulli_b2n(
int start_index,
unsigned number_of_bernoullis_b2n,
OutputIterator out_it);
template <class T, class OutputIterator, class Policy>
OutputIterator bernoulli_b2n(
int start_index,
unsigned number_of_bernoullis_b2n,
OutputIterator out_it,
const Policy& pol);
}}
Для вычисления нескольких чисел Бернулли с одним вызовом предоставляются две версии функции номера Бернулли (одна с политикой по умолчанию, а другая с политикой, определяемой пользователем).
Они возвращают ряд чисел Бернулли:
B2*start_index,B2*(start_index+1),...,B2*(start_index+number_of_bernoullis_b2n-1)
Мы можем вычислить и сохранить все поплавковые номера Бернулли от одного звонка.
std::vector<float> bn;
boost::math::bernoulli_b2n<float>(0, 32, std::back_inserter(bn));
for(size_t i = 0; i < bn.size(); i++)
{
std::cout << std::setprecision(std::numeric_limits<float>::digits10)
<< i*2 << ' '
<< bn[i]
<< std::endl;
}
0 1
2 0.166667
4 -0.0333333
6 0.0238095
8 -0.0333333
10 0.0757576
12 -0.253114
14 1.16667
16 -7.09216
18 54.9712
20 -529.124
22 6192.12
24 -86580.3
26 1.42552e+006
28 -2.72982e+007
30 6.01581e+008
32 -1.51163e+010
34 4.29615e+011
36 -1.37117e+013
38 4.88332e+014
40 -1.92966e+016
42 8.41693e+017
44 -4.03381e+019
46 2.11507e+021
48 -1.20866e+023
50 7.50087e+024
52 -5.03878e+026
54 3.65288e+028
56 -2.84988e+030
58 2.38654e+032
60 -2.14e+034
62 2.0501e+036
Конечно, для любого типа с плавающей точкой существует максимальное число Бернулли, которое можно вычислить, прежде чем оно переполнит показатель. По умолчанию, если мы попытаемся вычислить слишком высокое число Бернулли, будет сделано исключение.
try
{
std::cout
<< std::setprecision(std::numeric_limits<float>::digits10)
<< "Bernoulli number " << 33 * 2 <<std::endl;
std::cout << boost::math::bernoulli_b2n<float>(33) << std::endl;
}
catch (std::exception ex)
{
std::cout << "Thrown Exception caught: " << ex.what() << std::endl;
}
и мы получим полезное сообщение об ошибке (при условии использования блоков try'n'catch).
Bernoulli number 66
Thrown Exception caught: Error in function boost::math::bernoulli_b2n<float>(n):
Overflow evaluating function at 33
Источник этого примера находится по адресу bernoulli_example.cpp
Все функции обычно возвращают значения в пределах одного ULP (единица в последнем месте) для типа с плавающей точкой.
Детали реализации находятся в bernoulli_details.hpp и unchecked_bernoulli.hpp.
Для i max_bernoulli_index<T>::value
это реализовано простым поиском таблицы из статически инициализированной таблицы; для более крупных значений i
это реализовано алгоритмом Tangent Numbers, описанным в статье: Fast Computation of Bernoulli, Tangent and Secant Numbers, Richard P. Brent and David Harvey, http://arxiv.org/pdf/1108.0286v3.pdf (2011).
Опасные (или Заг) числа Определяется (четное переменное число перестановок), и в нем также дается их генерирующая функция.
Отношение чисел Тангента к числам Бернулли Bi дано уравнением Брента и Харви 14:

Их отношение к числам Бернулли Bi определяется
если i > 0 и i четно тогда
, если i == 0, то Bi = 1
, если i == 1, то Bi = -1/2
, если i < 0 или i нечетно, то Bi = 0
Обратите внимание, что вычисленные значения хранятся в таблице с фиксированным размером, доступ к потоку безопасен посредством атомных операций (т.е. свободного программирования блокировки), это дает гораздо более низкие накладные расходы на доступ к кэшированным значениям, чем можно было бы ожидать в противном случае - обычно для многоточных типов стоимость синхронизации потока ничтожна, в то время как для встроенных типов этот код обычно не выполняется в любом случае. Для очень больших аргументов, которые не могут быть разумно вычислены или сохранены в нашем кэше, используется асимптотическое расширение из-за Luschny:
