简体   繁体   English

自然对数 (ln) 和取幂的实现问题

[英]Issue with implementation of natural logarithm (ln) and exponentiation

I try to follow the topic "Efficient implementation of natural logarithm (ln) and exponentiation" to be able to implement a log function without math.h.我尝试遵循“自然对数 (ln) 和求幂的有效实现”主题,以便能够在没有 math.h 的情况下实现日志 function。 The described algorithm works well for values between 1 and 2 (normalized values).所描述的算法适用于 1 和 2 之间的值(归一化值)。 However, if the values are not normalized and I follow the normalization instructions, then I get wrong values.但是,如果这些值没有被规范化并且我按照规范化说明进行操作,那么我会得到错误的值。

Link: Click here链接: 点这里

If I follow the code with an exemplary integer value of 12510, I get the following results:如果我使用示例性 integer 值 12510 遵循代码,我会得到以下结果:

y = 12510 (0x30DE), log2 = 13, divisor = 26, x = 481,1538 y = 12510 (0x30DE),log2 = 13,除数 = 26,x = 481,1538

float ln(float y) {
    int log2;
    float divisor, x, result;

    log2 = msb((int)y); // See: https://stackoverflow.com/a/4970859/6630230
    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;
}

The expected result for x should be a normalized value of 1 < x < 2. However, I fail in this calculation, because the received result is 481,1538. x 的预期结果应该是 1 < x < 2 的标准化值。但是,我在这个计算中失败了,因为收到的结果是 481,1538。

Thanks in advance for any help提前感谢您的帮助

Out of curiosity, I tried to reproduce:出于好奇,我试图重现:

#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: https://stackoverflow.com/a/4970859/6630230
    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));
}

Output: Output:

log2: 13
divisor: 8192.000000
x: 1.527100
ln(12510): 9.434252

Live Demo on colirucoliru 现场演示

I just tried this in my Windows 7 Pocket calculator and got:我刚刚在我的 Windows 7 袖珍计算器中尝试了这个并得到:

9.434283603460956823997266847405

9,434283603460956823997266847405

The first 5 digits are identical.前 5 位数字相同。 – The rest I would consider as rounding issues whithout knowing which one got closer. – rest 我认为是舍入问题,但不知道哪个更接近。

However, there is a typo (or mistake) in the question:但是,问题中有一个错字(或错误):

y = 12510 (0x30DE), log2 = 13, divisor = 26, x = 481,1538 y = 12510 (0x30DE),log2 = 13,除数 = 26,x = 481,1538

divisor = (float)(1 << log2); with log2 = 13 yields 8192 . log2 = 13产生8192

log2 << 1 would result in 26 . log2 << 1将导致26

Just for fun, I changed the line into divisor = (float)(log2 << 1);只是为了好玩,我把这条线改成了divisor = (float)(log2 << 1); and got the following output:并得到以下 output:

log2: 13
divisor: 26.000000
x: 481.153839
ln(12510): -2982522368.000000

So, this leaves me a bit puzzled:所以,这让我有点困惑:

The exposed code seems to be correct but the OP seems to have it interpreted (or resembled) wrong.暴露的代码似乎是正确的,但 OP 似乎将其解释(或类似)错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM