自然对数 (ln) 和求幂的实施问题
Issue with implementation of natural logarithm (ln) and exponentiation
我尝试按照"Efficient implementation of natural logarithm (ln) and exponentiation"这个话题来实现不用math.h的日志功能。所描述的算法适用于 1 和 2 之间的值(归一化值)。但是,如果这些值未标准化并且我按照标准化说明进行操作,那么我会得到错误的值。
Link: Click here
如果我遵循示例整数值 12510 的代码,我会得到以下结果:
y = 12510 (0x30DE), log2 = 13, 除数 = 26, x = 481,1538
float ln(float y) {
int log2;
float divisor, x, result;
log2 = msb((int)y); // See:
divisor = (float)(1 << log2);
x = y / divisor; // normalized value between [1.0, 2.0]
result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
result += ((float)log2) * 0.69314718; // ln(2) = 0.69314718
return result;
}
x的预期结果应该是1 < x < 2的归一化值。但是,我在这个计算中失败了,因为收到的结果是481,1538。
在此先感谢您的帮助
出于好奇,我尝试重现:
#include <stdio.h>
int msb(unsigned int v) {
unsigned int r = 0;
while (v >>= 1) r++;
return r;
}
float ln(float y)
{
int log2;
float divisor, x, result;
log2 = msb((int)y); // See:
printf("log2: %d\n", log2);
divisor = (float)(1 << log2);
printf("divisor: %f\n", divisor);
x = y / divisor; // normalized value between [1.0, 2.0]
printf("x: %f\n", x);
result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
result += ((float)log2) * 0.69314718; // ln(2) = 0.69314718
return result;
}
int main()
{
printf("ln(12510): %f\n", ln(12510));
}
输出:
log2: 13
divisor: 8192.000000
x: 1.527100
ln(12510): 9.434252
我刚刚在我的 Windows 7 袖珍计算器中尝试了这个并得到:
9.434283603460956823997266847405
前 5 位数字相同。 – 其余的我会认为是四舍五入的问题,不知道哪个更接近。
但是,问题中有一个错字(或错误):
y = 12510 (0x30DE), log2 = 13, divisor = 26, x = 481,1538
divisor = (float)(1 << log2);
与 log2 = 13
产生 8192
.
log2 << 1
会导致 26
.
只是为了好玩,我将行改为 divisor = (float)(log2 << 1);
并得到以下输出:
log2: 13
divisor: 26.000000
x: 481.153839
ln(12510): -2982522368.000000
所以,这让我有点困惑:
公开的代码似乎是正确的,但 OP 似乎对其解释(或类似)错误。
我尝试按照"Efficient implementation of natural logarithm (ln) and exponentiation"这个话题来实现不用math.h的日志功能。所描述的算法适用于 1 和 2 之间的值(归一化值)。但是,如果这些值未标准化并且我按照标准化说明进行操作,那么我会得到错误的值。
Link: Click here
如果我遵循示例整数值 12510 的代码,我会得到以下结果:
y = 12510 (0x30DE), log2 = 13, 除数 = 26, x = 481,1538
float ln(float y) {
int log2;
float divisor, x, result;
log2 = msb((int)y); // See:
divisor = (float)(1 << log2);
x = y / divisor; // normalized value between [1.0, 2.0]
result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
result += ((float)log2) * 0.69314718; // ln(2) = 0.69314718
return result;
}
x的预期结果应该是1 < x < 2的归一化值。但是,我在这个计算中失败了,因为收到的结果是481,1538。
在此先感谢您的帮助
出于好奇,我尝试重现:
#include <stdio.h>
int msb(unsigned int v) {
unsigned int r = 0;
while (v >>= 1) r++;
return r;
}
float ln(float y)
{
int log2;
float divisor, x, result;
log2 = msb((int)y); // See:
printf("log2: %d\n", log2);
divisor = (float)(1 << log2);
printf("divisor: %f\n", divisor);
x = y / divisor; // normalized value between [1.0, 2.0]
printf("x: %f\n", x);
result = -1.7417939 + (2.8212026 + (-1.4699568 + (0.44717955 - 0.056570851 * x) * x) * x) * x;
result += ((float)log2) * 0.69314718; // ln(2) = 0.69314718
return result;
}
int main()
{
printf("ln(12510): %f\n", ln(12510));
}
输出:
log2: 13
divisor: 8192.000000
x: 1.527100
ln(12510): 9.434252
我刚刚在我的 Windows 7 袖珍计算器中尝试了这个并得到:
9.434283603460956823997266847405
前 5 位数字相同。 – 其余的我会认为是四舍五入的问题,不知道哪个更接近。
但是,问题中有一个错字(或错误):
y = 12510 (0x30DE), log2 = 13, divisor = 26, x = 481,1538
divisor = (float)(1 << log2);
与 log2 = 13
产生 8192
.
log2 << 1
会导致 26
.
只是为了好玩,我将行改为 divisor = (float)(log2 << 1);
并得到以下输出:
log2: 13
divisor: 26.000000
x: 481.153839
ln(12510): -2982522368.000000
所以,这让我有点困惑:
公开的代码似乎是正确的,但 OP 似乎对其解释(或类似)错误。