updated boost on windows
This commit is contained in:
@@ -9,7 +9,10 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
#include <boost/multiprecision/detail/number_base.hpp> // test for multiprecision types.
|
||||
#include <boost/type_traits/is_complex.hpp> // test for complex types
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
#include <stdexcept>
|
||||
@@ -65,7 +68,7 @@ inline void unpack_0(const Tuple& t, T& val) BOOST_MATH_NOEXCEPT(T)
|
||||
{
|
||||
using dummy::get;
|
||||
// Rely on ADL to find the correct overload of get:
|
||||
val = get<0>(t);
|
||||
val = get<0>(t);
|
||||
}
|
||||
|
||||
template <class T, class U, class V>
|
||||
@@ -267,8 +270,17 @@ T newton_raphson_iterate(F f, T guess, T min, T max, int digits, boost::uintmax_
|
||||
#endif
|
||||
if(fabs(delta * 2) > fabs(delta2))
|
||||
{
|
||||
// last two steps haven't converged, try bisection:
|
||||
delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
||||
// last two steps haven't converged.
|
||||
T shift = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
||||
if ((result != 0) && (fabs(shift) > fabs(result)))
|
||||
{
|
||||
delta = sign(delta) * result; // protect against huge jumps!
|
||||
}
|
||||
else
|
||||
delta = shift;
|
||||
// reset delta1/2 so we don't take this branch next time round:
|
||||
delta1 = 3 * delta;
|
||||
delta2 = 3 * delta;
|
||||
}
|
||||
guess = result;
|
||||
result -= delta;
|
||||
@@ -350,12 +362,11 @@ namespace detail{
|
||||
T f0(0), f1, f2;
|
||||
T result = guess;
|
||||
|
||||
T factor = static_cast<T>(ldexp(1.0, 1 - digits));
|
||||
T factor = ldexp(static_cast<T>(1.0), 1 - digits);
|
||||
T delta = (std::max)(T(10000000 * guess), T(10000000)); // arbitarily large delta
|
||||
T last_f0 = 0;
|
||||
T delta1 = delta;
|
||||
T delta2 = delta;
|
||||
|
||||
bool out_of_bounds_sentry = false;
|
||||
|
||||
#ifdef BOOST_MATH_INSTRUMENT
|
||||
@@ -415,13 +426,14 @@ namespace detail{
|
||||
T convergence = fabs(delta / delta2);
|
||||
if((convergence > 0.8) && (convergence < 2))
|
||||
{
|
||||
// last two steps haven't converged, try bisection:
|
||||
// last two steps haven't converged.
|
||||
delta = (delta > 0) ? (result - min) / 2 : (result - max) / 2;
|
||||
if(fabs(delta) > result)
|
||||
if ((result != 0) && (fabs(delta) > result))
|
||||
delta = sign(delta) * result; // protect against huge jumps!
|
||||
// reset delta2 so that this branch will *not* be taken on the
|
||||
// next iteration:
|
||||
delta2 = delta * 3;
|
||||
delta1 = delta * 3;
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(delta);
|
||||
}
|
||||
guess = result;
|
||||
@@ -431,7 +443,10 @@ namespace detail{
|
||||
// check for out of bounds step:
|
||||
if(result < min)
|
||||
{
|
||||
T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min))) ? T(1000) : T(result / min);
|
||||
T diff = ((fabs(min) < 1) && (fabs(result) > 1) && (tools::max_value<T>() / fabs(result) < fabs(min)))
|
||||
? T(1000)
|
||||
: (fabs(min) < 1) && (fabs(tools::max_value<T>() * min) < fabs(result))
|
||||
? ((min < 0) != (result < 0)) ? -tools::max_value<T>() : tools::max_value<T>() : T(result / min);
|
||||
if(fabs(diff) < 1)
|
||||
diff = 1 / diff;
|
||||
if(!out_of_bounds_sentry && (diff > 0) && (diff < 3))
|
||||
@@ -509,9 +524,10 @@ namespace detail{
|
||||
template <class T>
|
||||
static T step(const T& x, const T& f0, const T& f1, const T& f2) BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T))
|
||||
{
|
||||
using std::fabs;
|
||||
T ratio = f0 / f1;
|
||||
T delta;
|
||||
if(ratio / x < 0.1)
|
||||
if((x != 0) && (fabs(ratio / x) < 0.1))
|
||||
{
|
||||
delta = ratio + (f2 / (2 * f1)) * ratio * ratio;
|
||||
// check second derivative doesn't over compensate:
|
||||
@@ -554,10 +570,262 @@ inline T schroeder_iterate(F f, T guess, T min, T max, int digits) BOOST_NOEXCEP
|
||||
return schroder_iterate(f, guess, min, max, digits, m);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
|
||||
/*
|
||||
* Why do we set the default maximum number of iterations to the number of digits in the type?
|
||||
* Because for double roots, the number of digits increases linearly with the number of iterations,
|
||||
* so this default should recover full precision even in this somewhat pathological case.
|
||||
* For isolated roots, the problem is so rapidly convergent that this doesn't matter at all.
|
||||
*/
|
||||
template<class Complex, class F>
|
||||
Complex complex_newton(F g, Complex guess, int max_iterations=std::numeric_limits<typename Complex::value_type>::digits)
|
||||
{
|
||||
typedef typename Complex::value_type Real;
|
||||
using std::norm;
|
||||
using std::abs;
|
||||
using std::max;
|
||||
// z0, z1, and z2 cannot be the same, in case we immediately need to resort to Muller's Method:
|
||||
Complex z0 = guess + Complex(1,0);
|
||||
Complex z1 = guess + Complex(0,1);
|
||||
Complex z2 = guess;
|
||||
|
||||
do {
|
||||
auto pair = g(z2);
|
||||
if (norm(pair.second) == 0)
|
||||
{
|
||||
// Muller's method. Notation follows Numerical Recipes, 9.5.2:
|
||||
Complex q = (z2 - z1)/(z1 - z0);
|
||||
auto P0 = g(z0);
|
||||
auto P1 = g(z1);
|
||||
Complex qp1 = static_cast<Complex>(1)+q;
|
||||
Complex A = q*(pair.first - qp1*P1.first + q*P0.first);
|
||||
|
||||
Complex B = (static_cast<Complex>(2)*q+static_cast<Complex>(1))*pair.first - qp1*qp1*P1.first +q*q*P0.first;
|
||||
Complex C = qp1*pair.first;
|
||||
Complex rad = sqrt(B*B - static_cast<Complex>(4)*A*C);
|
||||
Complex denom1 = B + rad;
|
||||
Complex denom2 = B - rad;
|
||||
Complex correction = (z1-z2)*static_cast<Complex>(2)*C;
|
||||
if (norm(denom1) > norm(denom2))
|
||||
{
|
||||
correction /= denom1;
|
||||
}
|
||||
else
|
||||
{
|
||||
correction /= denom2;
|
||||
}
|
||||
|
||||
z0 = z1;
|
||||
z1 = z2;
|
||||
z2 = z2 + correction;
|
||||
}
|
||||
else
|
||||
{
|
||||
z0 = z1;
|
||||
z1 = z2;
|
||||
z2 = z2 - (pair.first/pair.second);
|
||||
}
|
||||
|
||||
// See: https://math.stackexchange.com/questions/3017766/constructing-newton-iteration-converging-to-non-root
|
||||
// If f' is continuous, then convergence of x_n -> x* implies f(x*) = 0.
|
||||
// This condition approximates this convergence condition by requiring three consecutive iterates to be clustered.
|
||||
Real tol = max(abs(z2)*std::numeric_limits<Real>::epsilon(), std::numeric_limits<Real>::epsilon());
|
||||
bool real_close = abs(z0.real() - z1.real()) < tol && abs(z0.real() - z2.real()) < tol && abs(z1.real() - z2.real()) < tol;
|
||||
bool imag_close = abs(z0.imag() - z1.imag()) < tol && abs(z0.imag() - z2.imag()) < tol && abs(z1.imag() - z2.imag()) < tol;
|
||||
if (real_close && imag_close)
|
||||
{
|
||||
return z2;
|
||||
}
|
||||
|
||||
} while(max_iterations--);
|
||||
|
||||
// The idea is that if we can get abs(f) < eps, we should, but if we go through all these iterations
|
||||
// and abs(f) < sqrt(eps), then roundoff error simply does not allow that we can evaluate f to < eps
|
||||
// This is somewhat awkward as it isn't scale invariant, but using the Daubechies coefficient example code,
|
||||
// I found this condition generates correct roots, whereas the scale invariant condition discussed here:
|
||||
// https://scicomp.stackexchange.com/questions/30597/defining-a-condition-number-and-termination-criteria-for-newtons-method
|
||||
// allows nonroots to be passed off as roots.
|
||||
auto pair = g(z2);
|
||||
if (abs(pair.first) < sqrt(std::numeric_limits<Real>::epsilon()))
|
||||
{
|
||||
return z2;
|
||||
}
|
||||
|
||||
return {std::numeric_limits<Real>::quiet_NaN(),
|
||||
std::numeric_limits<Real>::quiet_NaN()};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
|
||||
// https://stackoverflow.com/questions/48979861/numerically-stable-method-for-solving-quadratic-equations/50065711
|
||||
namespace detail
|
||||
{
|
||||
template<class T>
|
||||
inline T discriminant(T const & a, T const & b, T const & c)
|
||||
{
|
||||
T w = 4*a*c;
|
||||
T e = std::fma(-c, 4*a, w);
|
||||
T f = std::fma(b, b, -w);
|
||||
return f + e;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
auto quadratic_roots(T const& a, T const& b, T const& c)
|
||||
{
|
||||
using std::copysign;
|
||||
using std::sqrt;
|
||||
if constexpr (std::is_integral<T>::value)
|
||||
{
|
||||
// What I want is to write:
|
||||
// return quadratic_roots(double(a), double(b), double(c));
|
||||
// but that doesn't compile.
|
||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
if(a==0)
|
||||
{
|
||||
if (b==0 && c != 0)
|
||||
{
|
||||
return std::pair<double, double>(nan, nan);
|
||||
}
|
||||
else if (b==0 && c==0)
|
||||
{
|
||||
return std::pair<double, double>(0,0);
|
||||
}
|
||||
return std::pair<double, double>(-c/b, -c/b);
|
||||
}
|
||||
if (b==0)
|
||||
{
|
||||
double x0_sq = -double(c)/double(a);
|
||||
if (x0_sq < 0) {
|
||||
return std::pair<double, double>(nan, nan);
|
||||
}
|
||||
double x0 = sqrt(x0_sq);
|
||||
return std::pair<double, double>(-x0,x0);
|
||||
}
|
||||
double discriminant = detail::discriminant(double(a), double(b), double(c));
|
||||
if (discriminant < 0)
|
||||
{
|
||||
return std::pair<double, double>(nan, nan);
|
||||
}
|
||||
double q = -(b + copysign(sqrt(discriminant), double(b)))/T(2);
|
||||
double x0 = q/a;
|
||||
double x1 = c/q;
|
||||
if (x0 < x1) {
|
||||
return std::pair<double, double>(x0, x1);
|
||||
}
|
||||
return std::pair<double, double>(x1, x0);
|
||||
}
|
||||
else if constexpr (std::is_floating_point<T>::value)
|
||||
{
|
||||
T nan = std::numeric_limits<T>::quiet_NaN();
|
||||
if(a==0)
|
||||
{
|
||||
if (b==0 && c != 0)
|
||||
{
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
else if (b==0 && c==0)
|
||||
{
|
||||
return std::pair<T, T>(0,0);
|
||||
}
|
||||
return std::pair<T, T>(-c/b, -c/b);
|
||||
}
|
||||
if (b==0)
|
||||
{
|
||||
T x0_sq = -c/a;
|
||||
if (x0_sq < 0) {
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
T x0 = sqrt(x0_sq);
|
||||
return std::pair<T, T>(-x0,x0);
|
||||
}
|
||||
T discriminant = detail::discriminant(a, b, c);
|
||||
// Is there a sane way to flush very small negative values to zero?
|
||||
// If there is I don't know of it.
|
||||
if (discriminant < 0)
|
||||
{
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
T q = -(b + copysign(sqrt(discriminant), b))/T(2);
|
||||
T x0 = q/a;
|
||||
T x1 = c/q;
|
||||
if (x0 < x1)
|
||||
{
|
||||
return std::pair<T, T>(x0, x1);
|
||||
}
|
||||
return std::pair<T, T>(x1, x0);
|
||||
}
|
||||
else if constexpr (boost::is_complex<T>::value || boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_complex)
|
||||
{
|
||||
typename T::value_type nan = std::numeric_limits<typename T::value_type>::quiet_NaN();
|
||||
if(a.real()==0 && a.imag() ==0)
|
||||
{
|
||||
using std::norm;
|
||||
if (b.real()==0 && b.imag() && norm(c) != 0)
|
||||
{
|
||||
return std::pair<T, T>({nan, nan}, {nan, nan});
|
||||
}
|
||||
else if (b.real()==0 && b.imag() && c.real() ==0 && c.imag() == 0)
|
||||
{
|
||||
return std::pair<T, T>({0,0},{0,0});
|
||||
}
|
||||
return std::pair<T, T>(-c/b, -c/b);
|
||||
}
|
||||
if (b.real()==0 && b.imag() == 0)
|
||||
{
|
||||
T x0_sq = -c/a;
|
||||
T x0 = sqrt(x0_sq);
|
||||
return std::pair<T, T>(-x0, x0);
|
||||
}
|
||||
// There's no fma for complex types:
|
||||
T discriminant = b*b - T(4)*a*c;
|
||||
T q = -(b + sqrt(discriminant))/T(2);
|
||||
return std::pair<T, T>(q/a, c/q);
|
||||
}
|
||||
else // Most likely the type is a boost.multiprecision.
|
||||
{ //There is no fma for multiprecision, and in addition it doesn't seem to be useful, so revert to the naive computation.
|
||||
T nan = std::numeric_limits<T>::quiet_NaN();
|
||||
if(a==0)
|
||||
{
|
||||
if (b==0 && c != 0)
|
||||
{
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
else if (b==0 && c==0)
|
||||
{
|
||||
return std::pair<T, T>(0,0);
|
||||
}
|
||||
return std::pair<T, T>(-c/b, -c/b);
|
||||
}
|
||||
if (b==0)
|
||||
{
|
||||
T x0_sq = -c/a;
|
||||
if (x0_sq < 0) {
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
T x0 = sqrt(x0_sq);
|
||||
return std::pair<T, T>(-x0,x0);
|
||||
}
|
||||
T discriminant = b*b - 4*a*c;
|
||||
if (discriminant < 0)
|
||||
{
|
||||
return std::pair<T, T>(nan, nan);
|
||||
}
|
||||
T q = -(b + copysign(sqrt(discriminant), b))/T(2);
|
||||
T x0 = q/a;
|
||||
T x1 = c/q;
|
||||
if (x0 < x1)
|
||||
{
|
||||
return std::pair<T, T>(x0, x1);
|
||||
}
|
||||
return std::pair<T, T>(x1, x0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace tools
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_TOOLS_NEWTON_SOLVER_HPP
|
||||
|
||||
|
||||
Reference in New Issue
Block a user