Quellcode durchsuchen

Implement erfcx()

wip/image-kernel
Sam Hocevar vor 2 Jahren
Ursprung
Commit
01e1b2736d
2 geänderte Dateien mit 18 neuen und 5 gelöschten Zeilen
  1. +1
    -0
      include/lol/private/types/real.h
  2. +17
    -5
      include/lol/private/types/real.ipp

+ 1
- 0
include/lol/private/types/real.h Datei anzeigen

@@ -123,6 +123,7 @@ public:
template<typename U> friend real_t<U> expm1(real_t<U> const &x);
template<typename U> friend real_t<U> erf(real_t<U> const &x);
template<typename U> friend real_t<U> erfc(real_t<U> const &x);
template<typename U> friend real_t<U> erfcx(real_t<U> const &x);
template<typename U> friend real_t<U> log(real_t<U> const &x);
template<typename U> friend real_t<U> log2(real_t<U> const &x);
template<typename U> friend real_t<U> log10(real_t<U> const &x);


+ 17
- 5
include/lol/private/types/real.ipp Datei anzeigen

@@ -1180,7 +1180,7 @@ template<typename T> real_t<T> erf(real_t<T> const &x)
// FIXME: this test is inefficient; the series below converges slowly for 1≤x≤7,
// but on the other hand there are accuracy issues with the erfc() implementation
// in that range.
if (x > real_t<T>(7))
if (x >= real_t<T>(7))
return real_t<T>::R_1() - erfc(x);

auto sum = real_t<T>::R_0();
@@ -1201,13 +1201,25 @@ template<typename T> real_t<T> erf(real_t<T> const &x)
template<typename T> real_t<T> erfc(real_t<T> const &x)
{
// Strategy for erfc(x):
// - if x<1, erfc(x) = 1-erf(x)
// - if x≥1, erfc(x) = exp(-x²)/(x·sqrt(π))·sum((-1)^n·(2n-1)!!/(2x²)^n)
if (x < real_t<T>::R_1())
// - if x<7, erfc(x) = 1-erf(x)
// - if x≥7, erfc(x) = exp(-x²)·erfcx(x)
if (x < real_t<T>(7))
return real_t<T>::R_1() - erf(x);

return exp(-x * x) * erfcx(x);
}

template<typename T> real_t<T> erfcx(real_t<T> const &x)
{
// Strategy for erfc(x):
// - if x<7, erfc(x) = exp(x²)·(1-erf(x))
// - if x≥7, erfc(x) = sum((-1)^n·(2n-1)!!/(2x²)^n) / (x·sqrt(π))
auto sum = real_t<T>::R_0();
auto x2 = x * x;

if (x < real_t<T>(7))
return exp(x2) * (real_t<T>::R_1() - erf(x));

// XXX: The series does not converge, there is an optimal value around
// ⌊x²+0.5⌋. If maximum accuracy cannot be reached, we must stop summing
// when divergence is detected.
@@ -1223,7 +1235,7 @@ template<typename T> real_t<T> erfc(real_t<T> const &x)
prev = tmp;
}

return exp(-x2) / (x * sqrt(real_t<T>::R_PI())) * sum;
return sum / (x * sqrt(real_t<T>::R_PI()));
}

template<typename T> real_t<T> sinh(real_t<T> const &x)


Laden…
Abbrechen
Speichern