Skip to content

Commit 434a017

Browse files
committed
Merge branch 'develop'
2 parents d2390d4 + 15c40fa commit 434a017

File tree

3 files changed

+49
-43
lines changed

3 files changed

+49
-43
lines changed

doc/roots/roots.qbk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
template <class F, class T>
3030
T schroder_iterate(F f, T guess, T min, T max, int digits, std::uintmax_t& max_iter);
3131

32-
template <class F, class Complex>
33-
Complex complex_newton(F f, Complex guess, int max_iterations = std::numeric_limits<typename Complex::value_type>::digits);
32+
template <class F, class ComplexType>
33+
Complex complex_newton(F f, Complex guess, int max_iterations = std::numeric_limits<typename ComplexType::value_type>::digits);
3434

3535
template<class T>
3636
auto quadratic_roots(T const & a, T const & b, T const & c);

include/boost/math/tools/roots.hpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -790,35 +790,35 @@ inline T schroeder_iterate(F f, T guess, T min, T max, int digits) noexcept(poli
790790
* so this default should recover full precision even in this somewhat pathological case.
791791
* For isolated roots, the problem is so rapidly convergent that this doesn't matter at all.
792792
*/
793-
template<class Complex, class F>
794-
Complex complex_newton(F g, Complex guess, int max_iterations = std::numeric_limits<typename Complex::value_type>::digits)
793+
template<class ComplexType, class F>
794+
ComplexType complex_newton(F g, ComplexType guess, int max_iterations = std::numeric_limits<typename ComplexType::value_type>::digits)
795795
{
796-
typedef typename Complex::value_type Real;
796+
typedef typename ComplexType::value_type Real;
797797
using std::norm;
798798
using std::abs;
799799
using std::max;
800800
// z0, z1, and z2 cannot be the same, in case we immediately need to resort to Muller's Method:
801-
Complex z0 = guess + Complex(1, 0);
802-
Complex z1 = guess + Complex(0, 1);
803-
Complex z2 = guess;
801+
ComplexType z0 = guess + ComplexType(1, 0);
802+
ComplexType z1 = guess + ComplexType(0, 1);
803+
ComplexType z2 = guess;
804804

805805
do {
806806
auto pair = g(z2);
807807
if (norm(pair.second) == 0)
808808
{
809809
// Muller's method. Notation follows Numerical Recipes, 9.5.2:
810-
Complex q = (z2 - z1) / (z1 - z0);
810+
ComplexType q = (z2 - z1) / (z1 - z0);
811811
auto P0 = g(z0);
812812
auto P1 = g(z1);
813-
Complex qp1 = static_cast<Complex>(1) + q;
814-
Complex A = q * (pair.first - qp1 * P1.first + q * P0.first);
815-
816-
Complex B = (static_cast<Complex>(2) * q + static_cast<Complex>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
817-
Complex C = qp1 * pair.first;
818-
Complex rad = sqrt(B * B - static_cast<Complex>(4) * A * C);
819-
Complex denom1 = B + rad;
820-
Complex denom2 = B - rad;
821-
Complex correction = (z1 - z2) * static_cast<Complex>(2) * C;
813+
ComplexType qp1 = static_cast<ComplexType>(1) + q;
814+
ComplexType A = q * (pair.first - qp1 * P1.first + q * P0.first);
815+
816+
ComplexType B = (static_cast<ComplexType>(2) * q + static_cast<ComplexType>(1)) * pair.first - qp1 * qp1 * P1.first + q * q * P0.first;
817+
ComplexType C = qp1 * pair.first;
818+
ComplexType rad = sqrt(B * B - static_cast<ComplexType>(4) * A * C);
819+
ComplexType denom1 = B + rad;
820+
ComplexType denom2 = B - rad;
821+
ComplexType correction = (z1 - z2) * static_cast<ComplexType>(2) * C;
822822
if (norm(denom1) > norm(denom2))
823823
{
824824
correction /= denom1;

test/test_roots.cpp

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
#include <pch.hpp>
77

88
#define BOOST_TEST_MAIN
9+
10+
// See: https://github.com/boostorg/math/issues/1115
11+
#if __has_include(<X11/X.h>)
12+
# include <X11/X.h>
13+
#endif
14+
915
#include <boost/test/unit_test.hpp>
1016
#include <boost/test/tools/floating_point_comparison.hpp>
1117
#include <boost/test/results_collector.hpp>
@@ -438,10 +444,10 @@ void test_beta(T, const char* /* name */)
438444
}
439445

440446
#if !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) && !defined(BOOST_NO_CXX11_LAMBDAS)
441-
template <class Complex>
447+
template <class ComplexType>
442448
void test_complex_newton()
443449
{
444-
typedef typename Complex::value_type Real;
450+
typedef typename ComplexType::value_type Real;
445451
std::cout << "Testing complex Newton's Method on type " << boost::typeindex::type_id<Real>().pretty_name() << "\n";
446452
using std::abs;
447453
using std::sqrt;
@@ -451,11 +457,11 @@ void test_complex_newton()
451457

452458
Real tol = std::numeric_limits<Real>::epsilon();
453459
// p(z) = z^2 + 1, roots: \pm i.
454-
polynomial<Complex> p{{1,0}, {0, 0}, {1,0}};
455-
Complex guess{1,1};
456-
polynomial<Complex> p_prime = p.prime();
457-
auto f = [&](Complex z) { return std::make_pair<Complex, Complex>(p(z), p_prime(z)); };
458-
Complex root = complex_newton(f, guess);
460+
polynomial<ComplexType> p{{1,0}, {0, 0}, {1,0}};
461+
ComplexType guess{1,1};
462+
polynomial<ComplexType> p_prime = p.prime();
463+
auto f = [&](ComplexType z) { return std::make_pair<ComplexType, ComplexType>(p(z), p_prime(z)); };
464+
ComplexType root = complex_newton(f, guess);
459465

460466
BOOST_CHECK(abs(root.real()) <= tol);
461467
BOOST_CHECK_CLOSE(root.imag(), (Real)1, tol);
@@ -468,44 +474,44 @@ void test_complex_newton()
468474
// Test that double roots are handled correctly-as correctly as possible.
469475
// Convergence at a double root is not quadratic.
470476
// This sets p = (z-i)^2:
471-
p = polynomial<Complex>({{-1,0}, {0,-2}, {1,0}});
477+
p = polynomial<ComplexType>({{-1,0}, {0,-2}, {1,0}});
472478
p_prime = p.prime();
473479
guess = -guess;
474-
auto g = [&](Complex z) { return std::make_pair<Complex, Complex>(p(z), p_prime(z)); };
480+
auto g = [&](ComplexType z) { return std::make_pair<ComplexType, ComplexType>(p(z), p_prime(z)); };
475481
root = complex_newton(g, guess);
476482
BOOST_CHECK(abs(root.real()) < 10*sqrt(tol));
477483
BOOST_CHECK_CLOSE(root.imag(), (Real)1, tol);
478484

479485
// Test that zero derivatives are handled.
480486
// p(z) = z^2 + iz + 1
481-
p = polynomial<Complex>({{1,0}, {0,1}, {1,0}});
487+
p = polynomial<ComplexType>({{1,0}, {0,1}, {1,0}});
482488
// p'(z) = 2z + i
483489
p_prime = p.prime();
484-
guess = Complex(0,-boost::math::constants::half<Real>());
485-
auto g2 = [&](Complex z) { return std::make_pair<Complex, Complex>(p(z), p_prime(z)); };
490+
guess = ComplexType(0,-boost::math::constants::half<Real>());
491+
auto g2 = [&](ComplexType z) { return std::make_pair<ComplexType, ComplexType>(p(z), p_prime(z)); };
486492
root = complex_newton(g2, guess);
487493

488494
// Here's the other root, in case code changes cause it to be found:
489-
//Complex expected_root1{0, half<Real>()*(sqrt(static_cast<Real>(5)) - static_cast<Real>(1))};
490-
Complex expected_root2{0, -half<Real>()*(sqrt(static_cast<Real>(5)) + static_cast<Real>(1))};
495+
//ComplexType expected_root1{0, half<Real>()*(sqrt(static_cast<Real>(5)) - static_cast<Real>(1))};
496+
ComplexType expected_root2{0, -half<Real>()*(sqrt(static_cast<Real>(5)) + static_cast<Real>(1))};
491497

492498
BOOST_CHECK_CLOSE(expected_root2.imag(),root.imag(), tol);
493499
BOOST_CHECK(abs(root.real()) < tol);
494500

495501
// Does a zero root pass the termination criteria?
496-
p = polynomial<Complex>({{0,0}, {0,0}, {1,0}});
502+
p = polynomial<ComplexType>({{0,0}, {0,0}, {1,0}});
497503
p_prime = p.prime();
498-
guess = Complex(0, -boost::math::constants::half<Real>());
499-
auto g3 = [&](Complex z) { return std::make_pair<Complex, Complex>(p(z), p_prime(z)); };
504+
guess = ComplexType(0, -boost::math::constants::half<Real>());
505+
auto g3 = [&](ComplexType z) { return std::make_pair<ComplexType, ComplexType>(p(z), p_prime(z)); };
500506
root = complex_newton(g3, guess);
501507
BOOST_CHECK(abs(root.real()) < tol);
502508

503509
// Does a monstrous root pass?
504510
Real x = -pow(static_cast<Real>(10), 20);
505-
p = polynomial<Complex>({{x, x}, {1,0}});
511+
p = polynomial<ComplexType>({{x, x}, {1,0}});
506512
p_prime = p.prime();
507-
guess = Complex(0, -boost::math::constants::half<Real>());
508-
auto g4 = [&](Complex z) { return std::make_pair<Complex, Complex>(p(z), p_prime(z)); };
513+
guess = ComplexType(0, -boost::math::constants::half<Real>());
514+
auto g4 = [&](ComplexType z) { return std::make_pair<ComplexType, ComplexType>(p(z), p_prime(z)); };
509515
root = complex_newton(g4, guess);
510516
BOOST_CHECK(abs(root.real() + x) < tol);
511517
BOOST_CHECK(abs(root.imag() + x) < tol);
@@ -607,24 +613,24 @@ void test_solve_int_quadratic()
607613
BOOST_CHECK_CLOSE(p.second, double(7), tol);
608614
}
609615

610-
template<class Complex>
616+
template<class ComplexType>
611617
void test_solve_complex_quadratic()
612618
{
613-
using Real = typename Complex::value_type;
619+
using Real = typename ComplexType::value_type;
614620
Real tol = std::numeric_limits<Real>::epsilon();
615621
using boost::math::tools::quadratic_roots;
616-
auto [x0, x1] = quadratic_roots<Complex>({1,0}, {0,0}, {-1,0});
622+
auto [x0, x1] = quadratic_roots<ComplexType>({1,0}, {0,0}, {-1,0});
617623
BOOST_CHECK_CLOSE(x0.real(), Real(-1), tol);
618624
BOOST_CHECK_CLOSE(x1.real(), Real(1), tol);
619625
BOOST_CHECK_SMALL(x0.imag(), tol);
620626
BOOST_CHECK_SMALL(x1.imag(), tol);
621627

622-
auto p = quadratic_roots<Complex>({7,0}, {0,0}, {0,0});
628+
auto p = quadratic_roots<ComplexType>({7,0}, {0,0}, {0,0});
623629
BOOST_CHECK_SMALL(p.first.real(), tol);
624630
BOOST_CHECK_SMALL(p.second.real(), tol);
625631

626632
// (x-7)^2 = x^2 - 14*x + 49:
627-
p = quadratic_roots<Complex>({1,0}, {-14,0}, {49,0});
633+
p = quadratic_roots<ComplexType>({1,0}, {-14,0}, {49,0});
628634
BOOST_CHECK_CLOSE(p.first.real(), Real(7), tol);
629635
BOOST_CHECK_CLOSE(p.second.real(), Real(7), tol);
630636

0 commit comments

Comments
 (0)