#include <iostream>
#include <cmath>
#include <limits>
const double log_pi (1.1447298858494);
const double log_two_pi (1.83787706640935);
const double inv_sqrt_2pi(0.3989422804014327);
template<typename T = double>
auto normal_distribution_density(T x, T mu = 0, T sigma = 1)
{
auto const y = (x - mu) / sigma;
return 1 / (sigma * std::sqrt(2 * std::exp(log_pi))) * std::exp(-y * y / 2);
}
// https://g...content-available-to-author-only...b.com/tbrown122387/pf/blob/master/include/rv_eval.h#L140template<typename T = double>
template<typename float_t>
float_t evalUnivNorm(float_t x, float_t mu, float_t sigma, bool log)
{
float_t exponent = -.5*(x - mu)*(x-mu)/(sigma*sigma);
if( sigma > 0.0){
if(log){
return -std::log(sigma) - .5*log_two_pi + exponent;
}else{
return inv_sqrt_2pi * std::exp(exponent) / sigma;
}
}else{
if(log){
return -std::numeric_limits<float_t>::infinity();
}else{
return 0.0;
}
}
}
template<typename T = double>
auto wrapped_normal_distribution_density(T x, T mu = 0, T sigma = 1, T epsilon = 0)
{
T s = normal_distribution_density(x, mu, sigma);
for (int k = 1;; ++k)
{
T a = normal_distribution_density(x + k, mu, sigma),
b = normal_distribution_density(x - k, mu, sigma);
s += a + b;
if (a <= epsilon && b <= epsilon)
break;
}
return s;
}
// https://g...content-available-to-author-only...b.com/tbrown122387/pf/blob/23d0e94ff8bd987997efafad66c120c07aaeddee/include/rv_eval.h#L120
template<typename float_t>
float_t log_sum_exp(float_t a, float_t b)
{
float_t m = std::max(a,b);
return m + std::log(std::exp(a-m) + std::exp(b-m));
}
template<typename T = double>
auto wrapped_normal_distribution_density_taylor(T x, T mu = 0, T sigma = 1, T epsilon = 0)
{
// k=0
T log_result = evalUnivNorm(x, mu, sigma, true);
T last_iter_log_r;
for (int absk = 1; absk < 1000; absk++)
{
last_iter_log_r = log_result;
std::cout << "ay\n";
log_result = log_sum_exp<T>(log_result, evalUnivNorm<T>(x + absk, mu, sigma, true));
log_result = log_sum_exp<T>(log_result, evalUnivNorm<T>(x - absk, mu, sigma, true));
if (last_iter_log_r == log_result)
return std::exp(log_result);
}
}
int main() {
std::cout << "your eval: " << wrapped_normal_distribution_density<double>(10.0) << "\n";
std::cout << "my eval: " << wrapped_normal_distribution_density_taylor<double>(10.0) << "\n";
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8Y21hdGg+CiNpbmNsdWRlIDxsaW1pdHM+CgoKCmNvbnN0IGRvdWJsZSBsb2dfcGkgKDEuMTQ0NzI5ODg1ODQ5NCk7CmNvbnN0IGRvdWJsZSBsb2dfdHdvX3BpICgxLjgzNzg3NzA2NjQwOTM1KTsKY29uc3QgZG91YmxlIGludl9zcXJ0XzJwaSgwLjM5ODk0MjI4MDQwMTQzMjcpOwoKdGVtcGxhdGU8dHlwZW5hbWUgVCA9IGRvdWJsZT4KYXV0byBub3JtYWxfZGlzdHJpYnV0aW9uX2RlbnNpdHkoVCB4LCBUIG11ID0gMCwgVCBzaWdtYSA9IDEpCnsKICAgIGF1dG8gY29uc3QgeSA9ICh4IC0gbXUpIC8gc2lnbWE7CiAgICByZXR1cm4gMSAvIChzaWdtYSAqIHN0ZDo6c3FydCgyICogc3RkOjpleHAobG9nX3BpKSkpICogc3RkOjpleHAoLXkgKiB5IC8gMik7Cn0KCi8vIGh0dHBzOi8vZy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYi5jb20vdGJyb3duMTIyMzg3L3BmL2Jsb2IvbWFzdGVyL2luY2x1ZGUvcnZfZXZhbC5oI0wxNDB0ZW1wbGF0ZTx0eXBlbmFtZSBUID0gZG91YmxlPgp0ZW1wbGF0ZTx0eXBlbmFtZSBmbG9hdF90PgpmbG9hdF90IGV2YWxVbml2Tm9ybShmbG9hdF90IHgsIGZsb2F0X3QgbXUsIGZsb2F0X3Qgc2lnbWEsIGJvb2wgbG9nKQp7CiAgICBmbG9hdF90IGV4cG9uZW50ID0gLS41Kih4IC0gbXUpKih4LW11KS8oc2lnbWEqc2lnbWEpOwogICAgaWYoIHNpZ21hID4gMC4wKXsKICAgICAgICBpZihsb2cpewogICAgICAgICAgICByZXR1cm4gLXN0ZDo6bG9nKHNpZ21hKSAtIC41KmxvZ190d29fcGkgKyBleHBvbmVudDsKICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgcmV0dXJuIGludl9zcXJ0XzJwaSAqIHN0ZDo6ZXhwKGV4cG9uZW50KSAvIHNpZ21hOwogICAgICAgIH0KICAgIH1lbHNlewogICAgICAgIGlmKGxvZyl7CiAgICAgICAgICAgIHJldHVybiAtc3RkOjpudW1lcmljX2xpbWl0czxmbG9hdF90Pjo6aW5maW5pdHkoKTsKICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgcmV0dXJuIDAuMDsKICAgICAgICB9CiAgICB9Cn0KCnRlbXBsYXRlPHR5cGVuYW1lIFQgPSBkb3VibGU+CmF1dG8gd3JhcHBlZF9ub3JtYWxfZGlzdHJpYnV0aW9uX2RlbnNpdHkoVCB4LCBUIG11ID0gMCwgVCBzaWdtYSA9IDEsIFQgZXBzaWxvbiA9IDApCnsKCVQgcyA9IG5vcm1hbF9kaXN0cmlidXRpb25fZGVuc2l0eSh4LCBtdSwgc2lnbWEpOwoJZm9yIChpbnQgayA9IDE7OyArK2spCgl7CgkJVCBhID0gbm9ybWFsX2Rpc3RyaWJ1dGlvbl9kZW5zaXR5KHggKyBrLCBtdSwgc2lnbWEpLAoJCQliID0gbm9ybWFsX2Rpc3RyaWJ1dGlvbl9kZW5zaXR5KHggLSBrLCBtdSwgc2lnbWEpOwoJCXMgKz0gYSArIGI7CgkJaWYgKGEgPD0gZXBzaWxvbiAmJiBiIDw9IGVwc2lsb24pCgkJCWJyZWFrOwoJfQoJcmV0dXJuIHM7Cn0KCgovLyBodHRwczovL2cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmIuY29tL3Ricm93bjEyMjM4Ny9wZi9ibG9iLzIzZDBlOTRmZjhiZDk4Nzk5N2VmYWZhZDY2YzEyMGMwN2FhZWRkZWUvaW5jbHVkZS9ydl9ldmFsLmgjTDEyMAp0ZW1wbGF0ZTx0eXBlbmFtZSBmbG9hdF90PgpmbG9hdF90IGxvZ19zdW1fZXhwKGZsb2F0X3QgYSwgZmxvYXRfdCBiKQp7CiAgICBmbG9hdF90IG0gPSBzdGQ6Om1heChhLGIpOwogICAgcmV0dXJuIG0gKyBzdGQ6OmxvZyhzdGQ6OmV4cChhLW0pICsgc3RkOjpleHAoYi1tKSk7Cn0KCnRlbXBsYXRlPHR5cGVuYW1lIFQgPSBkb3VibGU+CmF1dG8gd3JhcHBlZF9ub3JtYWxfZGlzdHJpYnV0aW9uX2RlbnNpdHlfdGF5bG9yKFQgeCwgVCBtdSA9IDAsIFQgc2lnbWEgPSAxLCBUIGVwc2lsb24gPSAwKQp7CgkvLyBrPTAKCVQgbG9nX3Jlc3VsdCA9IGV2YWxVbml2Tm9ybSh4LCBtdSwgc2lnbWEsIHRydWUpOwoJVCBsYXN0X2l0ZXJfbG9nX3I7Cglmb3IgKGludCBhYnNrID0gMTsgYWJzayA8IDEwMDA7IGFic2srKykKCXsKCQlsYXN0X2l0ZXJfbG9nX3IgPSBsb2dfcmVzdWx0OwoJCXN0ZDo6Y291dCA8PCAiYXlcbiI7CgkJbG9nX3Jlc3VsdCA9IGxvZ19zdW1fZXhwPFQ+KGxvZ19yZXN1bHQsIGV2YWxVbml2Tm9ybTxUPih4ICsgYWJzaywgbXUsIHNpZ21hLCB0cnVlKSk7CgkJbG9nX3Jlc3VsdCA9IGxvZ19zdW1fZXhwPFQ+KGxvZ19yZXN1bHQsIGV2YWxVbml2Tm9ybTxUPih4IC0gYWJzaywgbXUsIHNpZ21hLCB0cnVlKSk7CgkJaWYgKGxhc3RfaXRlcl9sb2dfciA9PSBsb2dfcmVzdWx0KQoJCQlyZXR1cm4gc3RkOjpleHAobG9nX3Jlc3VsdCk7Cgl9Cn0KCgoKCmludCBtYWluKCkgewoKCXN0ZDo6Y291dCA8PCAieW91ciBldmFsOiAiIDw8IHdyYXBwZWRfbm9ybWFsX2Rpc3RyaWJ1dGlvbl9kZW5zaXR5PGRvdWJsZT4oMTAuMCkgPDwgIlxuIjsKCXN0ZDo6Y291dCA8PCAibXkgZXZhbDogIiA8PCB3cmFwcGVkX25vcm1hbF9kaXN0cmlidXRpb25fZGVuc2l0eV90YXlsb3I8ZG91YmxlPigxMC4wKSA8PCAiXG4iOwoJcmV0dXJuIDA7Cn0=