Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Root-finding using Boost.Multiprecision

Boost , Math Toolkit 2.5.0 , Examples of Root-Finding (with and without derivatives)

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Апокрифически проницательный читатель может теперь спросить: «Как мы узнаем, вычисляет ли это «правильный» ответ?»

Для большинства ценностей, к сожалению, нет «правильного» ответа. Это связано с тем, что значения редко могут бытьточно представленытипами с плавающей точкой C++. То, что мы действительно хотим, — это «лучшее» представление, которое является ближайшимрепрезентабельным значением. (Подробнее о том, как представлены числа см.Плавающая точка).

Конечно, мы могли бы начать с поиска внешнего источника отсчета, такого какWolfram Alpha, как указано выше, но это не всегда возможно.

Другой способ успокоить — вычислить «ссылочные» значения с более высокой точностью, чтобы сравнить результаты наших итеративных вычислений с использованием встроенного<double>. Они должны согласиться в рамках установленной терпимости.

Результат от<static_cast>ing до<double>от более высокоточного типа, такого как<cpp_bin_float_50>, гарантированно будетближайшим репрезентабельным<double>значением.

Например, функции корня куба в нашем примере для<cbrt(28.)>вычисления

<std::cbrt<double>(28.)= 3.0365889718756627>

Вольфрам Альфа говорит<3.036588971875662519420809578505669635581453977248111123242141...>

<static_cast<double>(3.03658897187566251942080957850) =3.0365889718756627>

Этот пример<cbrt(28.)= 3.0365889718756627>

[Tip] Tip

Чтобы гарантировать, что все потенциально значимые десятичные цифры отображаются, используйте<std::numeric_limits<T>::max_digits10>(или если они не доступны на старых платформах или компиляторах, используйте<2+std::numeric_limits<double>::digits*3010/10000>).

В идеале значения должны соответствовать<std::numeric-limits<T>::digits10>десятичным цифрам.

Это также означает, что «справочное» значение, которое должно бытьвходнымили<static_cast>, должно иметь по меньшей мере<max_digits10>десятичных цифр (17 для 64-битного<double>.

Если мы хотим вычислитьзначения более высокой точности, то на некоторых платформах мы можем использовать<long double>с более высокой точностью, чем<double>, для сравнения с очень распространенным<double>и/или более эффективным встроенным типом квадратной плавающей точки, таким как<__float128>.

Почти все платформы могут легко использоватьBoost.Multiprecision, например,cpp_dec_floatили бинарный типcpp_bin_floatдля вычисления значений с гораздо большей точностью.

[Note] Note

С многоточными типами спорно, использовать ли тип<T>для вычисления исходных догадок. Тип<double>является достаточно точным для метода, используемого в этих примерах. Это ограничит диапазон возможных значений<double>. Кроме того, существует стоимость преобразования в тип<T>и из него. В этих примерах<double>используется<typedefdouble guess_type>.

Поскольку функторы и функции, используемые выше, шаблонизированы по типу значения, мы можем очень просто использовать их с любым из типовBoost.Multiprecision. В качестве напоминания, вот наша корневая функция игрушечного куба, использующая 2 производных и функции лямбды C++11, чтобы найти корень:

template <class T>
T cbrt_2deriv_lambda(T x)
{
   // return cube root of x using 1st and 2nd derivatives and Halley.
   //using namespace std;  // Help ADL of std functions.
   using namespace boost::math::tools;
   int exponent;
   frexp(x, &exponent);                                // Get exponent of z (ignore mantissa).
   T guess = ldexp(1., exponent / 3);                    // Rough guess is to divide the exponent by three.
   T min = ldexp(0.5, exponent / 3);                     // Minimum possible value is half our guess.
   T max = ldexp(2., exponent / 3);                      // Maximum possible value is twice our guess.
   const int digits = std::numeric_limits<T>::digits;  // Maximum possible binary digits accuracy for type T.
   // digits used to control how accurate to try to make the result.
   int get_digits = static_cast<int>(digits * 0.4);    // Accuracy triples with each step, so stop when just
   // over one third of the digits are correct.
   boost::uintmax_t maxit = 20;
   T result = halley_iterate(
      // lambda function:
      [x](const T& g){ return std::make_tuple(g * g * g - x, 3 * g * g, 6 * g); },
      guess, min, max, get_digits, maxit);
   return result;
}

Ниже приведены примеры 50 десятичных знаков и двоичных типов (а на некоторых платформах гораздо более быстрый<float128>или<quad_float>тип), которые мы можем использовать с ними:

#include <boost/multiprecision/cpp_bin_float.hpp> // For cpp_bin_float_50.
#include <boost/multiprecision/cpp_dec_float.hpp> // For cpp_dec_float_50.
#ifndef _MSC_VER  // float128 is not yet supported by Microsoft compiler at 2013.
#  include <boost/multiprecision/float128.hpp> // Requires libquadmath.
#endif

Некоторые заявления упрощают их использование:

  using boost::multiprecision::cpp_dec_float_50; // decimal.
  using boost::multiprecision::cpp_bin_float_50; // binary.
#ifndef _MSC_VER  // Not supported by Microsoft compiler.
  using boost::multiprecision::float128;
#endif

Их можно использовать таким образом:

std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
cpp_dec_float_50 two = 2; // 
cpp_dec_float_50  r = cbrt_2deriv(two);
std::cout << "cbrt(" << two << ") = " << r << std::endl;
r = cbrt_2deriv(2.); // Passing a double, so ADL will compute a double precision result.
std::cout << "cbrt(" << two << ") = " << r << std::endl;
// cbrt(2) = 1.2599210498948731906665443602832965552806854248047 'wrong' from digits 17 onwards!
r = cbrt_2deriv(static_cast<cpp_dec_float_50>(2.)); // Passing a cpp_dec_float_50, 
// so will compute a cpp_dec_float_50 precision result.
std::cout << "cbrt(" << two << ") = " << r << std::endl;
r = cbrt_2deriv<cpp_dec_float_50>(2.); // Explictly a cpp_dec_float_50, so will compute a cpp_dec_float_50 precision result.
std::cout << "cbrt(" << two << ") = " << r << std::endl;
// cpp_dec_float_50 1.2599210498948731647672106072782283505702514647015

Исходное значение, вычисляемоеWolfram Alpha

N[2^(1/3), 50]  1.2599210498948731647672106072782283505702514647015

Что точно согласуется.

Чтобыпоказатьзначения с их полной точностью, необходимо отрегулировать<std::ostream><precision>в соответствии с типом, например:

template <typename T>
T show_cube_root(T value)
{ // Demonstrate by printing the root using all definitely significant digits.
  std::cout.precision(std::numeric_limits<T>::digits10);
  T r = cbrt_2deriv(value);
  std::cout << "value = " << value << ", cube root =" << r << std::endl;
  return r;
}
show_cube_root(2.);
show_cube_root(2.L);
show_cube_root(two);

который выдает:

cbrt(2) = 1.2599210498948731647672106072782283505702514647015
value = 2, cube root =1.25992104989487
value = 2, cube root =1.25992104989487
value = 2, cube root =1.2599210498948731647672106072782283505702514647015
[Tip] Tip

Будьте очень осторожныв отношении типа плавающей точки<T>, который передается функции поиска корней. Неосторожное прохождение целого числа путем написания<cpp_dec_float_50r =cbrt_2deriv(2);>или<show_cube_root(2);>вызовет много предупреждений и ошибок компиляции.

Даже<show_cube_root(2.F);>будет производить предупреждения, потому что<typedef doubleguess_type>определяет тип, используемый для вычисления значений догадок и скобок<double>.

Еще более коварным является прохождение<double>, как в<cpp_dec_float_50r=cbrt_2deriv(2.);>, который молча дает «неправильный» результат, вычисляя<double>результат изатемпреобразование в<cpp_dec_float_50>! Все цифры<max_digits10>будут неверными. Если вы сделаете вид<cbrt>явным с<cbrt_2deriv<cpp_dec_float_50>(2.);>, вы получите желаемый результат с точностью до 50 десятичных цифр.

Полный код этого примера находится по адресуroot_finding_multiprecision_example.cpp.


PrevUpHomeNext

Статья Root-finding using Boost.Multiprecision раздела Math Toolkit 2.5.0 Examples of Root-Finding (with and without derivatives) может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Examples of Root-Finding (with and without derivatives) ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 20:08:07/0.010293960571289/1