0

这可能是一个基本问题。我是 C++ 新手,我想实现一个可能不适合内存的巨大随机矩阵。所以我想也许我应该将它写入一个文件并在流中逐个元素地读取。

我要检查的是,如果元素小于阈值。如果是,则将元素(i,j)的索引压入一个stl向量中进行存储,如果否,则转到下一个元素。

基本上我需要几行将矩阵AJM写入matrix.dat,然后将其元素读取为:

for (int i = 0; i < ROWS; i++)
{
    for (int j = 0; j < COLS; j++)
    {
        currentElement = "read AJM[i][j] from matrix.txt";
    } 
}

所以“从matrix.txt读取AJM[i][j]”对我来说不是很清楚,我猜这是通过将文件指针迭代到i和j给出的某个特定位置来完成的,并指定要读取多少字节,对吧?

您能否向我展示 C++ 代码,以便matrix.dat在知道其索引的情况下一个一个地写入和读取元素,这样我就可以避免将整个矩阵存储在内存中?

太感谢了!

4

3 回答 3

4

你可能在这里重新发明轮子。如果矩阵是密集的,基本上有两种选择:列优先(Fortran 兼容)或行优先(C 多维数组兼容)。如果矩阵是稀疏的,那么有一些标准格式可供您选择最合适的(即三对角矩阵与“一般”稀疏矩阵的选择不同),CSR/CSC 可能是最普遍的“非常一般” ” 稀疏矩阵表示。您选择的内存中表示将在很大程度上通知基于磁盘的表示。我的建议:找到并使用一个可以做你想做的事的库,不要重新发明轮子。

你已经回答了矩阵是密集的,我有点/有点想回答我认为你应该问的问题,而不是你实际问的问题。如果你真的有一个巨大的矩阵(比如十亿个元素)存储为text,你将会有一个非常非常糟糕的时间,所以我将假设矩阵存储为双精度数以使生活更轻松.

尽管还有其他可能性,但密集矩阵基本上有两种简单的磁盘表示:行优先顺序和列优先顺序。i,j选择其中之一后,在知道矩阵维度的情况下,有两种选择用于获取索引并从文件中检索该值。假设矩阵维度是m(行)乘n(列),那么元素对应的矩阵开始的偏移量i,j是(对于行主顺序):

offset = i*n + j

或(对于列主顺序):

offset = j*m + i

假设矩阵元素都是双精度的,那么您可以seek()通过这个偏移量进入文件,对于行主要顺序执行类似的操作(其中mfsastd::ifstream附加到矩阵文件):

double element;
mfs.seekg( (i*n+j)*sizeof(double) );
mfs.read( reinterpret_cast<char*>(&element), sizeof(double) );

或者,在类似 POSIX 的系统上,您可以使用mmap()将矩阵文件映射到内存并使用相同的原理来计算适当的偏移量。

于 2013-09-18T21:54:43.063 回答
0

如何读取矩阵取决于如何写入矩阵。就个人而言,我会从指定矩阵的宽度和高度开始编写矩阵,然后将每一行写成一行。为简单起见,我将矩阵写为文本文件,例如,如下所示:

3 4
1 2 3 4
5 6 7 8
9 10 11 12

读取这样的矩阵非常简单:

int rows(0), columns(0);
if (in >> rows >> columns) {
    std::vector<std::vector<double>> matrix(rows);
    for (int r(0); in && r != rows; ++r) {
        std::copy_n(std::istream_iterator<double>(in), columns,
                    std::back_inserter(matrix[r]));
    }
}
if (!in) {
    std::cout << "ERROR: failed to read matrix\n";
}

显然,如果您已经有一个矩阵结构,您可以使用类似的方法直接填充矩阵的各个元素。要仅存储某些元素或其坐标,您可以将std::copy_n()函数替换为有条件地调用具有相应坐标的方法的东西,例如,

template <typename InIt, typename Predicate, typename Fun>
void filter_n(InIt it, int n, Predicate pred, Fun fun) {
    for (int i = 0; i != n; ++i, ++it) {
        if (pred(*it)) {
            fun(*it, i);
        }
    }
}

...然后用std::copy_n()合适的调用这个函数来替换,例如,

    filter_n(std::istream_iterator<double>(in), columns,
             [threshold](double d){ return d < threshold; },
             [r](double, int c) { std::cout << "(" << r << ", " << c << ")\n"; });

这只会打印小于 的元素的坐标,threshold但应该很容易将这些坐标以及该位置的值存储到合适的容器中。

于 2013-09-18T21:33:38.410 回答
0

如果你想使用一个文件,你将不得不决定你要存储的数据的编码。

天真的实现是按顺序存储每个元素,在下一行之前按顺序执行每一行(或列)。

无论您使用什么编码,如果它不适合内存,您将不得不使用允许重新定位以找到正确元素的文件句柄。具体如何工作将取决于您用于从文件加载的内容。

大多数情况下,该操作被称为Seek或一些小的变化。

于 2013-09-18T21:24:18.283 回答