blob: 79efd80f016ec5593949b47feac2b65f89a54174 [file] [log] [blame]
#include <limits>
#include "../../Eigen/Core"
extern "C" {
float slamch_(char* cmach);
double dlamch_(char* cmach);
float slamc3_(char* cmach);
double dlamc3_(char* cmach);
}
// Determines machine parameters.
template <typename T>
T xlamch(const char c) {
if (c == 'E' || c == 'e') {
// eps = relative machine precision. Looking at
// https://gcc.gnu.org/onlinedocs/gfortran/EPSILON.html observe that it is
// the smallest number E such that 1 + E > 1. It is NOT the same as
// numeric_limits::epsilon, which is the difference between 1 and the
// floating point number that succeeds it.
return std::numeric_limits<T>::epsilon() / std::numeric_limits<T>::radix;
}
if (c == 'S' || c == 's') {
// sfmin = safe minimum, such that 1 / sfmin does not overflow
EIGEN_CONSTEXPR T tiny = std::numeric_limits<T>::min();
EIGEN_CONSTEXPR T small = T(1) / std::numeric_limits<T>::max();
EIGEN_CONSTEXPR T small_scaled =
small * (T(1) + std::numeric_limits<T>::epsilon());
return (small >= tiny) ? small_scaled : tiny;
}
if (c == 'B' || c == 'b') {
// base = base of the machine.
return std::numeric_limits<T>::radix;
}
if (c == 'P' || c == 'p') {
// prec = eps * base
return std::numeric_limits<T>::epsilon();
}
if (c == 'N' || c == 'n') {
// t = number of (base) digits in the mantissa
return std::numeric_limits<T>::digits;
}
if (c == 'R' || c == 'r') {
// rnd = 1.0 when rounding occurs in addition.
return 1;
}
if (c == 'M' || c == 'm') {
// emin = minimum exponent before (gradual) underflow
return std::numeric_limits<T>::min_exponent;
}
if (c == 'U' || c == 'u') {
// rmin = underflow threshold - base**(emin-1)
return std::numeric_limits<T>::min();
}
if (c == 'L' || c == 'l') {
// emax = largest exponent before overflow
return std::numeric_limits<T>::max_exponent;
}
if (c == 'O' || c == 'o') {
// rmax = overflow threshold - (base**emax)*(1-eps)
return std::numeric_limits<T>::max();
}
return 0;
}
float slamch_(char* cmach) { return xlamch<float>(*cmach); }
double dlamch_(char* cmach) { return xlamch<double>(*cmach); }
// xLAMC3 is intended to force A and B to be stored prior to doing
// the addition of A and B , for use in situations where optimizers
// might hold one of these in a register.
float slamc3_(float* a, float* b) {
volatile float retval = *a + *b;
return retval;
}
double dlamc3_(double* a, double* b) {
volatile double retval = *a + *b;
return retval;
}