繁体   English   中英

以下C代码有什么好处?

[英]What are the benefits of the following C code?

给定log(a)和log(b),返回log(a + b)

double log_sum(double log_a, double log_b){
    double v;
    if(log_a < log_b){
        v=log_b+log(1+exp(log_a-log_b));
    }
    else{
        v=log_a+log(1+exp(log_b-log_a));
    }
    return v;
}

我想知道上述功能有什么好处?

主要(蛮力)替代方案如下:

v = log(exp(log_a) + exp(log_b));

这有三个超越功能评估。

显示的计算仅使用两个超越函数 - 并且应该更快。

它在数值上也可能更稳定。

计算机和日志并不总是相处得很好。 正如其他人所提到的那样,准确性成为一个真正的问题。 这篇博客文章对解释这一现象大有帮助。 这篇文章是关于看似不必要的库函数,以及为什么它们实际上非常方便。

函数log1p计算log(1 + x)。 这有多难实现?

在处理日志/指数时,您可以使用各种疯狂规则和变换。 我猜测的是,作者使用了其中一些规则来使计算更准确,更有效,或两者兼而有之。

其他人已经提到了潜在的精度损失,但在这种情况下问题确实是溢出 尝试这个:

double log_a = 100;
double log_b = 1000;
printf("%f\n", log_b+log(1+exp(log_a-log_b)));
printf("%f\n", log_a+log(1+exp(log_b-log_a)));

在典型的平台上,第一个将打印“inf”,而第二个将打印“1000.000000”。

如果你的意思是与log(exp(log_a) + exp(log_b)) ,那么好处是非常清楚的; 你提到的方式只需要计算一个日志和一个exp,而这种方式必须计算两个exps。 这比额外的加/减/测试要昂贵得多。

不是一个答案,但可能是一个线索。

以“日志形式”保存的数字可以通过简单地加上或减去数字来相乘或除以。 例如, exp(log(a) + log(b))a * b相同。 或者,使用a = 41,b = 101,这将是exp(3.71357 + 4.61512) ,即exp(8.32869)4140.98930 显然精确度起作用,我将数字截断为5位数。 41 * 1014141

我没有完成你的示例代码,也没有立即明白为什么你的代码按照它的方式做事情,但希望上面的代码可以帮助你把它拼凑起来。

编辑:我通过您的示例代码运行了一些数字。 如果a = 41且b = 101,log_a = 3.71357且log_b = 4.61512,则示例代码计算4.95582exp(4.95582)等于142.0 获得相同结果的“更简单”方法是log(exp(log_a) + exp(log_b)) ,但正如其他人所指出的那样,这种方式涉及三个昂贵的超越函数,而你的示例代码只需要两个(加上一个普通的比较)。

我想你问为什么这个函数比直接计算log(a+b)更好,通过恢复ab ,求和它们并计算log()

 log( exp( log_a ) + exp( log_b ) )

在这种情况下,您需要计算指数两次,并且在函数中,您询问指数只计算一次。 由于计算指数相对耗时,可能更快。

其他人已经发布了为什么要这样做的好答案。 我想知道if / else部分。 无论log_a还是log_b都更大, v两个表达式都应该等于log(a+b) 在每种情况下, 0 < exp( ... ) <= 1 ,并且log(1+exp( ... ))是一个小的正数。 出于某种原因,我不知道这一定是好的。

如果你问的是if / else,那就是为了避免精度损失。 对浮点数的所有算术运算(乘以2的幂和除了相同指数的加法/减法的某些情况除外)都会破坏信息,良好的浮点代码将选择具有最小精度损失的方法。

暂无
暂无

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

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