簡體   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