同时处理大量数字和分钟数

时间:2014-07-17 12:42:27

标签: matlab matrix floating-point-precision numerical

我有一个mxn矩阵A,有非常小或非常大的元素。例如:

A = -1e4*randn(10,20);

我想创建一个大小相同的新矩阵C,如下所示:

首先,定义一个矩阵B,其元素是A:

元素的指数
B = exp(A)

然后,定义矩阵C,使得C的每列与B的对应列成比例,并且C的每列的总和等于1.换句话说,如果我们采用B的元素并且除以它通过相同列的所有元素的总和,然后我们获得C:

的相应元素
C = bsxfun(@rdivide,B,sum(B));

在数学上:

enter image description here

显然,C的所有元素都在0和1之间。但是,当使用以下代码进行计算时,获得的矩阵包含许多NaN:

A = -1e4*randn(10,20);

B = exp(A);

C = bsxfun(@rdivide,B,sum(B));

sum(sum(isnan(ee)))

我希望有人可以建议一种方法来克服这个问题。非常感谢你提前。

更新:请注意,目标是矩阵C.我定义矩阵B仅用于解释目的,我们可能不必计算它。 (我们实际上不应该。因为@ EJG89指出B只包含Inf和0)。

更新2:感谢@ EJG89提供了Log Sum of Exponentials technique的链接,这可能很有用。我正在努力为我的问题寻找类似的分析技巧。

更新3:正如@Dan和@ EJG89所建议的那样,我们可以用常数减去每一列,以获得合理范围内的新矩阵。显然,我们有

enter image description here

对于任何常数C.我们可以选择C作为每列的最大值:

enter image description here

(a_ {max,j}是第j列的最大值),然后

enter image description here

我觉得这个选择可能会给出非常好的近似值,但我不知道它有多好:|

新代码是:

A = bsxfun(@minus,A,max(A));
B = exp(A);
C = bsxfun(@rdivide,B,sum(B));

4 个答案:

答案 0 :(得分:3)

您想将 A 调整为一些新的 A&#39; ,以便 e A = Ce A&# 39; 其中 C 是一个常数(远小于1)。换句话说,您正在寻找一些 k ,以便 ke A 足够小,不会违反ndoublemax或{ {1}}。但是我们希望将 k 应用于 A ,因此我们需要将它放入指数中。 k = e ln(k) 和e ln(k) .e A = e < sup> A + ln(k) 因此,如果我们从eps加上或减去一个数字, e A 会按比例生效。或 A&#39; = A + ln(k)

不幸的是,我认为你的范围太大,无法让任何 ln(k)阻止你超越Matlab双打的限制。如果你添加一个大数字,你将A的所有B等于inf,如果你减去一个大数字,你将得到B的全部等于零。

所以你需要找到一些同时使用大量数字和分钟数的方法。

答案 1 :(得分:0)

直接方法是不可能的。

A = -1e4*randn(10,20);
B = exp(A);

问题是B已经产生Inf或0。

让分裂不可能归还南楠。

ndoublemax = realmax
nsinglemax = realmax('single')

ndoublemin = realmin
nsinglemin = realmin('single')

得到以下特性:

ndoublemax =

1.7977e + 308

nsinglemax =

3.4028e + 038

ndoublemin =

2.2251e-308

nsinglemin =

1.1755e-038

所以B的值明显超过了这些值。

可以通过以下方式重写指数来进行近似: http://lingpipe-blog.com/2009/06/25/log-sum-of-exponentials/

首先改写为: log(Cij)= log(exp(Aij)/ sumk(exp(A(kj))))

log(Cij)= Aij - log(sumk(exp(A(kj)))

其中最后一项可以近似为: m = maxk(A(kj))

log(sumk(exp(A(kj)))= m + log(exp(A(kj)-m))

这导致MatLab能够处理更小的值,即可以说是标准化。尽管如此,仍然没有确切的答案,因为有些值会变为零,从而消除了它们有时的重要贡献

亲切的问候,

Ernst Jan

答案 2 :(得分:0)

在讨论了@ EJG89之后,您可以使用最大可表示数字替换无限值,然后将eps添加到分母中的所有数字。这样就避免了Inf

A = -1e4*randn(10,20);

B = exp(A);
B(isinf(B)) = realmax;

C = bsxfun(@rdivide,B,sum(B)+eps);

sum(isnan(C(:)))

答案 3 :(得分:0)

一种方法可能是采用符号计算:

A = -1e4*randn(10,20);
S = sym(A,'d'); %// convert to symbolic
C = exp(S)./repmat(sum(exp(S)),size(S,1),1);

结果C以符号形式给出。例如,第一列将类似于

>> C(:,1)
ans =
   2.9347694526167482187885232843876*10^(-790)
  1.548257079197982942994953632259*10^(-10497)
  8.4257350773369612716806306890481*10^(-6390)
  3.1937456016712092927990884814437*10^(-7937)
  4.0377045095817442881784227420794*10^(-4076)
                                           1.0
  3.3704875581881026436375125643672*10^(-6482)
 8.9221015470879963245101895439354*10^(-12246)
 9.4968643813486260650483647051531*10^(-11252)
 1.8777491443104052522832960625121*10^(-11084)

但请注意,即使使用符号计算,最大项也是1,实际上它(稍微)更小。当然,如果你转换为double,你只能获得0或1个值:

>> Cd = eval(C);
>> Cd(:,1)
ans =
     0
     0
     0
     0
     0
     1
     0
     0
     0
     0