非常小的值的平均数含义

3

我正在尝试计算一些非常小的值的平均数的对数。对于当前的数据集,极端点是

log_a=-1.6430e+03;
log_b=-3.8278e+03;

因此,实际上我想计算(a+b) / 2log((a+b)/2),因为我知道(a+b)/2作为double类型存储太小了。
我考虑尝试通过填充常量来解决问题,这样我就不必存储log_a,而是存储log_a+c,但似乎ab之间相差太大了,为了使exp(log_b+c)可计算,我需要填充log_b的值,但这将导致exp(log_a+c)变得太大。
我是否忽略了一些明显的计算方法?据我所知,MATLAB只能使用双精度,所以我对如何进行这个简单的计算感到困惑。
编辑:澄清一下:我可以计算出这些特定值的确切答案。对于算法的其他运行,这些值将不同且可能更接近。到目前为止,已经有一些好的近似方法建议;如果实现精确解决方案不可行,是否还有其他适用于更普遍数字/值大小的近似方法?

1
我有点困惑。(exp(log_a) + exp(log_b)) / 2 不就是 ab 的平均值吗?原始值的平均数的对数更像是 log((a+b)/2)(虽然要得到这些值的平均数,你不能只取极值并将它们平均)。 - Dusty
是的,你说得对;抱歉让你感到困惑。我对ab的平均值感兴趣,但我知道ab都太小了,无法表示为双精度数,因此实际上我要找的是log((a+b)/2)而不是(a+b)/2 - bnaul
1
啊,我明白了。正如Mysticial指出的那样,由于ab的数量级相差很大,将它们相加实际上不会影响a的值长达几百位小数(远超双精度范围),因此log((a+b)/2)会降为log(a/2)log_a-log(2) - Dusty
你是否考虑过使用符号工具箱进行变量精度算术运算? - Amro
我刚刚更新了我的答案,提供了一个完整的算法,可以在不损失精度的情况下准确地实现你想要的功能。 - Mysticial
我刚刚在我的答案中添加了一个更简单的解决方案。 - Mysticial
4个回答

4

好的,exp(log_b)exp(log_a)小得多,您可以完全忽略该项并仍然获得关于双精度的正确答案:

exp(log_a) = 2.845550077506*10^-714
exp(log_b) = 4.05118588390*10^-1663

如果你正在尝试计算(exp(log_a) + exp(log_b)) / 2,答案将会下溢至零。因此,除非你打算在最后再次取对数,否则这并不重要。
如果你正在尝试计算:
log((exp(log_a) + exp(log_b)) / 2)

你最好检查log_alog_b之间的差异。如果差异很大,那么最终值可以等于更大的项- log(2),因为较小的项足够小而完全消失。

编辑:

因此,你的最终算法可能如下所示:

  1. 检查大小。如果abs(log_a-log_b)>800,则返回max(log_a,log(b))-log(2)
  2. 检查任何一个大小(此时它们将非常接近)。如果比1大或小得多,请从log_alog_b中添加/减去一个常数。
  3. 执行计算。
  4. 如果在步骤2中缩放了值,则将结果缩放回来。

编辑2:

这是更好的解决方案:

if (log_a > log_b)
    return log_a + log(1 + exp(log_b - log_a)) - log(2)
else
    return log_b + log(1 + exp(log_a - log_b)) - log(2)

如果log_alog_b不太大或为负数,则此方法可行。


这是一个很好的答案,让我感到有些安慰。然而,一般情况下,在算法的其他运行中,这些值可能会更接近(请参见我的问题中的澄清)。我认为这个和我的之前的想法结合起来可能会奏效。特别是:将“c”添加到所有值中,使最大值变得可计算;计算“log(mean(exp(x+c)))-c”;仍然下溢的值可以假定对计算没有影响。让我再考虑一下,但我认为这会奏效。谢谢! - bnaul
如果值足够接近于重要的位置,但又足够大/小以至于exp()会溢出/下,则是的,您需要将这些值缩放以避免溢出。 - Mysticial

4

Mystical的想法是正确的,但为了得到更普遍的解决方案,可以使用以下方法,它可以给出一个向量log_v的算术平均数的对数:

max_log = max(log_v);
logsum = max_log + log(sum(exp(log_v-max_log)));
logmean = logsum - log(length(log_v));

这是统计机器学习中常见的问题,因此如果您在谷歌搜索logsum.m,您会发现几个不同版本的MATLAB函数,研究人员为此编写了这些函数。例如,这里是一个Github链接,它使用与sum相同的调用约定。


我同意,这是解决一般问题的最佳方案。谢谢! - bnaul

0

好的,如果你不喜欢我之前提出的完全更换平台的建议,而是在寻找一种近似方法,为什么不使用几何平均数(exp((log_a+log_b)/2))呢?


-1

使用 http://wolframalpha.com 。例如,正如Mysticial所讨论的那样,您计算的log(exp(-1.6430e+03) + exp(-3.8278e+03)/2)大约等于log_a。 更确切地说,它等于...

1642.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999288154175193167154874243862288962865800888654829363675488466381404578225092913407982036991983506370017587380105049077722517705727311433458060227246074261903850589008701929721367650576354241270720062760800558681236724831345952032973775644175750495894596292205385323394564549904750849335403418234531787942293155499938538026848481952030717783105220543888597195156662520697417952130625416040662694927878196360733032741542418365527213770518383992577797346467266676866552563022498785887306273550235307330535082355570343750317349638125974233837177558240980392298326807001406291035229026016040567173260205109683449441154277953394697235601979288239733693137185710713089424316870093563207034737497769711306780243623361236030692934897720786516684985651633787662244416960982457075265287065358586526093347161275192566468776617613339812566918101457823704547101340270795298909954224594...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接