c++ 中的下三角阵矩阵元标记

若有一个下三角阵,不包括对角元,其矩阵元为

\[A_{ij}, ~~~~ i = 1, \cdots, n-1, ~~~~ j=0,\cdots, i-1. \]

那么,可以用一维数组储存这些矩阵元:

\[a[k] = A_{ij}, ~~~ k = i(i-1)/2 + j. \]

这样可以将 \(k=0,\cdots,n(n-1)/2-1\)\((i,j)\) 实现一一对应,如此可以紧凑地储存下三角阵。如果需要包括对角元,我相信稍微调整一下上式,也可以类似地实现。

那么,如果已知 \(k\),欲求 \(i,j\),则可以如下使用:

\[i = [ \sqrt{2k+0.25}+ 0.5 + 10^{-9} ],~~ j = k - i(i-1)/2. \]

证明如下:

\[i(i-1)/2 \leq k \leq i(i-1)/2 + i-1, \\ i^2-i \leq 2k \leq i^2 + i -2, \\ i-0.5 \leq \sqrt{ 2k+0.25 } \leq \sqrt{ (i+0.5)^2 -2 } , \\ i \leq \sqrt{ 2k+0.25 } + 0.5 \leq \sqrt{ (i+0.5)^2 -2 } + 0.5, \\ \]

理论上可以取

\[i = [ \sqrt{ 2k+0.25 } + 0.5 ], \]

但是这里有一点担心:如果 \(2k+0.25\) 开根号,得到的数比真实值稍微少一点点,\(\sqrt{2k+0.25}+0.5\) 取整的话,就有可能得到\(i-1\)
所以需要给 \(\sqrt{2k+0.25}+0.5\) 加一点点,再取整,但是如果加多了,上确界可能又超过 \(i+1\),麻烦,所以先看看 \(i+1\) 和上确界 \(- \sqrt{ (i+0.5)^2 -2 } - 0.5\) 之间的距离随着 \(i\) 怎么变:

\[i+1 - \sqrt{ (i+0.5)^2 -2 } - 0.5 = \frac{2}{ i+0.5 + \sqrt{ (i+0.5)^2 -2 } } < \frac{2}{2i+1} < \frac{1}{i}, \]

是单调递减的,在 \(i\) 特别大的时候趋于 \(\frac{1}{i}\)
所以,可以加个 \(10^{-9}\),只有在 \(i\)\(10^9\) 左右的时候,才会出问题。

\[i = [ \sqrt{2k+0.25}+ 0.5 + 10^{-9} ],~~ j = k - i(i-1)/2. \]

特别鸣谢我雷哥,发现了这个开根号的 round-off 可能带来的问题,修正如上。

posted on 2021-06-29 19:32  luyi07  阅读(172)  评论(0编辑  收藏  举报

导航