b2/core/include/bertini2/num_traits.hpp
2025-01-14 01:15:53 +01:00

321 lines
6.0 KiB
C++

//This file is part of Bertini 2.
//
//num_traits.hpp is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//num_traits.hpp is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with num_traits.hpp. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright(C) 2015 - 2021 by Bertini2 Development Team
//
// See <http://www.gnu.org/licenses/> for a copy of the license,
// as well as COPYING. Bertini2 is provided with permitted
// additional terms in the b2/licenses/ directory.
// individual authors of this file include:
// silviana amethyst, university of wisconsin eau claire
/**
\file num_traits.hpp
\brief Provides an Eigen-like NumTraits struct for querying traits of a number type.
The bertini::NumTraits struct provides NumDigits and NumFuzzyDigits functions.
*/
#ifndef BERTINI_NUM_TRAITS_HPP
#define BERTINI_NUM_TRAITS_HPP
#include <random>
#include <complex>
#include <cmath>
#include "bertini2/mpfr_complex.hpp"
#include "bertini2/random.hpp"
namespace bertini
{
template<typename T>
T RandomUnit();
template<typename T>
struct NumTraits
{};
template <> struct NumTraits<double>
{
inline static unsigned NumDigits()
{
return 16;
}
inline static unsigned NumFuzzyDigits()
{
return 14;
}
inline
static unsigned TolToDigits(double tol)
{
return ceil(-log10(tol));
}
inline static
double FromString(std::string const& s)
{
return boost::lexical_cast<double>(s);
}
inline static
double FromRational(mpq_rational const& n, unsigned /* precision */)
{
return double(n);
}
using Real = double;
using Complex = dbl_complex;
};
template <> struct NumTraits<dbl_complex >
{
inline static unsigned NumDigits()
{
return 16;
}
inline static unsigned NumFuzzyDigits()
{
return 14;
}
inline static
dbl_complex FromString(std::string const& s)
{
return boost::lexical_cast<dbl_complex>(s);
}
inline static
dbl_complex FromString(std::string const& s, std::string const& t)
{
return dbl_complex(boost::lexical_cast<double>(s),boost::lexical_cast<double>(t));
}
inline static
dbl_complex FromRational(mpq_rational const& n, unsigned /* precision */)
{
return dbl_complex(static_cast<double>(n),0);
}
using Real = double;
using Complex = dbl_complex;
};
inline
unsigned PrecisionIncrement()
{
return 10;
}
inline
unsigned DoublePrecision()
{
return 16;
}
inline
unsigned LowestMultiplePrecision()
{
return 20;
}
inline
unsigned MaxPrecisionAllowed()
{
return 1000;
}
/**
\brief Get the precision of a number.
For doubles, this is trivially 16.
*/
inline
unsigned Precision(double)
{
return DoublePrecision();
}
/**
For complex doubles, throw if the requested precision is not DoublePrecision.
*/
inline
void Precision(double, unsigned prec)
{
if (prec!=DoublePrecision())
{
std::stringstream err_msg;
err_msg << "trying to change precision of a double to " << prec;
throw std::runtime_error(err_msg.str());
}
}
/**
\brief Get the precision of a number.
For complex doubles, this is trivially 16.
*/
inline
unsigned Precision(dbl_complex)
{
return DoublePrecision();
}
/**
For complex doubles, throw if the requested precision is not DoublePrecision.
*/
inline
void Precision(dbl_complex, unsigned prec)
{
if (prec!=DoublePrecision())
{
std::stringstream err_msg;
err_msg << "trying to change precision of a double to " << prec;
throw std::runtime_error(err_msg.str());
}
}
inline
dbl_complex rand_complex()
{
using std::abs;
using std::sqrt;
static std::default_random_engine generator;
static std::uniform_real_distribution<double> distribution(-1.0,1.0);
dbl_complex returnme(distribution(generator), distribution(generator));
return returnme / sqrt( abs(returnme));
}
template <> inline
dbl_complex RandomUnit<dbl_complex >()
{
static std::default_random_engine generator;
static std::uniform_real_distribution<double> distribution(-1.0,1.0);
dbl_complex returnme(distribution(generator), distribution(generator));
return returnme / abs(returnme);
}
template <>
inline
mpfr_complex RandomUnit<mpfr_complex>()
{
return multiprecision::RandomUnit();
}
}// re: namespace bertini
namespace bertini {
template <> struct NumTraits<mpfr_float>
{
inline static unsigned NumDigits()
{
return DefaultPrecision();
}
inline static unsigned NumFuzzyDigits()
{
return DefaultPrecision()-3;
}
inline
static unsigned TolToDigits(mpfr_float tol)
{
mpfr_float b = ceil(-log10(tol));
return b.convert_to<unsigned int>();
}
inline static
mpfr_float FromString(std::string const& s)
{
return mpfr_float(s);
}
inline static
mpfr_float FromRational(mpq_rational const& n, unsigned precision)
{
return mpfr_float(n,precision);
}
using Real = mpfr_float;
using Complex = mpfr_complex;
};
template <> struct NumTraits<mpfr_complex>
{
inline static unsigned NumDigits()
{
return DefaultPrecision();
}
inline static
mpfr_complex FromString(std::string const& s)
{
return mpfr_complex(s);
}
inline static
mpfr_complex FromString(std::string const& s, std::string const& t)
{
return mpfr_complex(s,t);
}
inline static
mpfr_complex FromRational(mpq_rational const& n, unsigned precision)
{
return mpfr_complex(n,0,precision);
}
using Real = mpfr_float;
using Complex = mpfr_complex;
};
template <> struct NumTraits<mpq_rational>
{
inline static
mpq_rational FromString(std::string const& s)
{
return mpq_rational(s);
}
};
}
#endif