如何用 C++ 编写一个以 10 为底的日志函数?
How to write a log base 10 function in c++?
我知道这似乎是一个重复的问题,但我在之前的问题中找不到我的答案。
我的意思是如何通过简单的循环而不是使用 C++ 中的内置日志函数来编写一个以 10 为底的日志函数。
假设 "log base 10" 你的意思是 "the number of times n can be divided by 10 before resulting in a value < 10":
log = 0;
// Assume n has initial value N
while ( n >= 10 ) {
// Invariant: N = n * 10^log
n /= 10;
log += 1;
}
最简单的方法是用 Taylor series 计算自然对数 (ln)。找到自然对数后,只需将其除以 ln(10) 即可得到以 10 为底的对数。
泰勒级数在 C 中实现起来非常简单。如果 z
是您要查找对数的数字,您只需循环几次迭代,将累加器乘以 (z-1)
每一次。在一定程度上,您 运行 的迭代次数越多,您的结果就越准确。针对 libC log10()
版本检查几次,直到您对精度感到满意为止。
这是一个"numeric approach"。还有其他数字解决方案可以提供更准确的结果来查找数字的对数。其中一些可以在我给你的维基百科 link 中找到。
使用牛顿法可以更快地收敛。使用类似这样的东西(手写未编译或测试使用 f(r) = 2**r - x 来计算 log2(x) ):
double next(double r, double x) {
static double one_over_ln2 = 1.4426950408889634;
return r - one_over_ln2 * (1 - x / (1 << static_cast<int>(r)));
double log2(double x) {
static double epsilon = 0.000000001; // change this to change accuracy
double r = x / 2;. // better first guesses converge faster
double r2 = next(r, x);
double delta = r - r2;
while (delta * delta > epsilon) {
r = r2;
r2 = next(r, x);
delta = r - r2
}
return r2;
}
double log10(double x) {
static double log2_10 = log2(10);
return log2(x) / log2_10;
}
我知道这似乎是一个重复的问题,但我在之前的问题中找不到我的答案。 我的意思是如何通过简单的循环而不是使用 C++ 中的内置日志函数来编写一个以 10 为底的日志函数。
假设 "log base 10" 你的意思是 "the number of times n can be divided by 10 before resulting in a value < 10":
log = 0;
// Assume n has initial value N
while ( n >= 10 ) {
// Invariant: N = n * 10^log
n /= 10;
log += 1;
}
最简单的方法是用 Taylor series 计算自然对数 (ln)。找到自然对数后,只需将其除以 ln(10) 即可得到以 10 为底的对数。
泰勒级数在 C 中实现起来非常简单。如果 z
是您要查找对数的数字,您只需循环几次迭代,将累加器乘以 (z-1)
每一次。在一定程度上,您 运行 的迭代次数越多,您的结果就越准确。针对 libC log10()
版本检查几次,直到您对精度感到满意为止。
这是一个"numeric approach"。还有其他数字解决方案可以提供更准确的结果来查找数字的对数。其中一些可以在我给你的维基百科 link 中找到。
使用牛顿法可以更快地收敛。使用类似这样的东西(手写未编译或测试使用 f(r) = 2**r - x 来计算 log2(x) ):
double next(double r, double x) {
static double one_over_ln2 = 1.4426950408889634;
return r - one_over_ln2 * (1 - x / (1 << static_cast<int>(r)));
double log2(double x) {
static double epsilon = 0.000000001; // change this to change accuracy
double r = x / 2;. // better first guesses converge faster
double r2 = next(r, x);
double delta = r - r2;
while (delta * delta > epsilon) {
r = r2;
r2 = next(r, x);
delta = r - r2
}
return r2;
}
double log10(double x) {
static double log2_10 = log2(10);
return log2(x) / log2_10;
}