首先,我使用的是自然对数的近似值。或查看此处(4.1.27) 以获得更好的公式表示。
这是我的实现:
constexpr double eps = 1e-12;
constexpr double my_exp(const double& power)
{
double numerator = 1;
ull denominator = 1;
size_t count = 1;
double term = numerator / denominator;
double sum = 0;
while (count < 20)
{
sum += term;
numerator *= power;
#ifdef _DEBUG
if (denominator > std::numeric_limits<ull>::max() / count)
throw std::overflow_error("Denominator has overflown at count " + std::to_string(count));
#endif // _DEBUG
denominator *= count++;
term = numerator / denominator;
}
return sum;
}
constexpr double E = my_exp(1);
constexpr double my_log(const double& num)
{
if (num < 1)
return my_log(num * E) - 1;
else if (num > E)
return my_log(num / E) + 1;
else
{
double s = 0;
size_t tmp_odd = 1;
double tmp = (num - 1) / (num + 1);
double mul = tmp * tmp;
while (tmp >= eps)
{
s += tmp;
tmp_odd += 2;
tmp *= mul / tmp_odd;
}
return 2 * s;
}
}
您可能会明白我为什么要实现这些功能。基本上,我想实现一个 pow 函数。但是我的方法仍然给出了非常不精确的答案,例如 my_log(10) = 2.30256,但根据 google (ln 10 ~ 2.30259)。
my_exp() 非常精确,因为它的泰勒展开是高度收敛的。根据谷歌,my_exp(1) = 2.718281828459,同时 e^1 = 2.71828182846。但不幸的是,自然对数的情况并非如此,我什至不知道自然对数的这个系列是如何派生的(我的意思是来自上面的链接)。而且我找不到关于这个系列的任何来源。
精度误差从何而来?