将矢量创建的 Matlab 代码翻译成 C++
Translating Matlab code of vector creation to C++
我有这个 Matlab 代码:
[arr1 arr2 arr3] = fReadFileBin(filename));
函数体是:
function [Result1 , Result2 , Result3 ] = fReadFileBin(filename)
fid = fopen(filename, 'r');
fseek(fid, 180, 0);
PV = fread(fid, [A*3 B+2], 'float32');
fclose(fid);
Result1 = PV(1:3:3*A, 2:B+1);
Result1 = Result1';
Result2 = PV(2:3:3*A, 2:B+1);
Result2 = Result2';
Result3 = PV(3:3:3*A, 2:B+1);
Result3 = Result3';
结果我有 3 个填充向量,大小为 B
xA
,类型为 Double。
当我尝试用 C++ 重写它时:
std::vector<std::vector<double>> result;
result.resize(B, std::vector<double>(A));
std::ifstream is(filename, std::ios::binary);
is.seekg(0, std::ios_base::end);
std::size_t size = is.tellg();
is.seekg(0, std::ios_base::beg);
is.seekg( 180, 0);
std::vector<double> PV (size / sizeof(double));
if (!is.read((char*)&PV[0], size))
{
throw std::runtime_error("error reading file");
}
// Load the data
is.read((char*)&PV[0], size);
is.close();
// std::vector<double> Result1 =
// std::vector<double> Result2 =
// std::vector<double> Result3 =
//R=R'
//R[j][i] = R[i][j];
对我来说确实有意义,但仍然不明白如何重写这部分:(1:3:3*A, 2:B+1)
in C++ ?
备注:
-我仅限于使用标准库(没有 boost、mmap 等)。
-我检查了有关冒号的 Mathwork 文档(但仍然无法理解如何实现它)。
由于向量的结果大小是固定的,我宁愿使用 std::array:
std::array<std::vector<double>, 3> result;
也不再调整大小,反正看起来会简单得多:
//result.resize(B, std::vector<double>(A));
result.resize(3);
通过这一行,您的外部向量现在恰好包含三个向量 - 每个向量都是空的 - 就像数组方法一样。无论你最终 select 是哪个,你都需要明确地调整内部向量的大小。不过,我们稍后会再谈这个。
is.seekg(0, std::ios_base::end);
std::size_t size = is.tellg(); // OK, you fetched file size
//is.seekg(0, std::ios_base::beg); // using beg, you can give the desired offset directly
//is.seekg( 180, 0); // but use the seekdir enum! So:
is.seekg(180, std::ios_base::beg);
但是,您应该检查之前至少有 180 字节的文件。您应该知道这些操作中的 any 可能会失败,因此您应该检查流的状态,在每个单个操作之后或至少在其中几个操作之后(因此至少在调整大小之前你的向量 PV
)。旁注:如果流已经处于失败状态,则每个后续操作也将失败,除非您 clear()
之前的错误状态。
std::vector<double> PV (size / sizeof(double));
呃,我觉得很奇怪...你从偏移量 180 开始,所以我认为你应该在除法之前减去;一世。即:
size_t size = ...;
if(size < 180) // bad file!
{
// throw or whatever appropriate
}
size -= 180;
// go on...
如果没有此修复,下一行将 总是 导致抛出以下异常,因为您会读取超出文件末尾的内容(请记住,您是从文件开始读取的偏移 180!):
if (!is.read((char*)&PV[0], size))
但更喜欢 C++ 风格的转换:
if (!is.read(reinterpret_cast<char*>(PV.data()), size))
您会很快发现您需要 reinterpret_cast
,有时是合适的,但在大多数情况下,如果您考虑使用它,至少应该敲响警钟,它只是隐藏了一些更深层次的问题,例如未定义的行为。 PV.data()
自 C++11 以来就存在并且比 &PV[0]
更容易阅读,但两者是等价的。
但是,我们现在还有一个不同的问题:
虽然该标准没有说明任何关于精度甚至格式的信息 ("The value representation of floating-point types is implementation-defined."),但在您的系统上,double 很可能是 64 位 IEEE754 数据类型。您真的确定数据正是以这种格式存储的吗?只有这样,这个 才能 工作,但是,它是非常危险的,文件生产者和消费者可能会说不同的语言,并且很可能你得到错误的输入...
现在承认,我根本不是matlab专家,但你的下面这行让我强烈怀疑上面的输入格式是否适用:
PV = fread(fid, [A*3 B+2], 'float32');
^^
最后,你已经读取你的数据已经在if
子句中,所以放弃这个第二行,它只会产生另一个失败...
如果现在数据不是以二进制形式存储,而是以人类可读的格式存储,您可以读取如下值:
std::vector<double> pv; // prefer lower camel case variable names
pv.reserve(size/sizeof(double)); // just using as a size hint;
// we can't deduce number of entries
// from file length exactly any more
double v;
while(is >> v)
{
pv.push_back(v);
}
if(!v.eof())
{
// we did not consume the whole file, so we must
// assume that some input error occurred!
// -> appropriate error handling (throw?)
}
慢慢走到尽头:
// std::vector<double> Result1 =
// std::vector<double> Result2 =
// std::vector<double> Result3 =
注释掉;对,你不需要它们,你已经在结果 vector/array 中有了它们,我。 e. result[0]
、result[1]
和 result[2]
...
根据需要调整它们的大小(或保留)以将结果数据放入并继续。
很抱歉,我现在不太清楚你的 matlab 计算是做什么的,我也不会为了这个答案而学习 matlab——不过,有了上面的提示,你可能会相处得很好。进一步提示:您不能将 vectors/arrays 作为一个整体相互相乘或直接与标量相乘;您必须在循环中分别为每个元素执行此操作。您可能会考虑 std::valarray an interesting alternative, though. Additionally, you might find some interesting stuff in the algorithm library,尤其是在 "numeric operations" 部分下。如果您对这些不满意,请随时提出另一个问题...
我有这个 Matlab 代码:
[arr1 arr2 arr3] = fReadFileBin(filename));
函数体是:
function [Result1 , Result2 , Result3 ] = fReadFileBin(filename)
fid = fopen(filename, 'r');
fseek(fid, 180, 0);
PV = fread(fid, [A*3 B+2], 'float32');
fclose(fid);
Result1 = PV(1:3:3*A, 2:B+1);
Result1 = Result1';
Result2 = PV(2:3:3*A, 2:B+1);
Result2 = Result2';
Result3 = PV(3:3:3*A, 2:B+1);
Result3 = Result3';
结果我有 3 个填充向量,大小为 B
xA
,类型为 Double。
当我尝试用 C++ 重写它时:
std::vector<std::vector<double>> result;
result.resize(B, std::vector<double>(A));
std::ifstream is(filename, std::ios::binary);
is.seekg(0, std::ios_base::end);
std::size_t size = is.tellg();
is.seekg(0, std::ios_base::beg);
is.seekg( 180, 0);
std::vector<double> PV (size / sizeof(double));
if (!is.read((char*)&PV[0], size))
{
throw std::runtime_error("error reading file");
}
// Load the data
is.read((char*)&PV[0], size);
is.close();
// std::vector<double> Result1 =
// std::vector<double> Result2 =
// std::vector<double> Result3 =
//R=R'
//R[j][i] = R[i][j];
(1:3:3*A, 2:B+1)
in C++ ?
备注:
-我仅限于使用标准库(没有 boost、mmap 等)。
-我检查了有关冒号的 Mathwork 文档(但仍然无法理解如何实现它)。
由于向量的结果大小是固定的,我宁愿使用 std::array:
std::array<std::vector<double>, 3> result;
也不再调整大小,反正看起来会简单得多:
//result.resize(B, std::vector<double>(A));
result.resize(3);
通过这一行,您的外部向量现在恰好包含三个向量 - 每个向量都是空的 - 就像数组方法一样。无论你最终 select 是哪个,你都需要明确地调整内部向量的大小。不过,我们稍后会再谈这个。
is.seekg(0, std::ios_base::end);
std::size_t size = is.tellg(); // OK, you fetched file size
//is.seekg(0, std::ios_base::beg); // using beg, you can give the desired offset directly
//is.seekg( 180, 0); // but use the seekdir enum! So:
is.seekg(180, std::ios_base::beg);
但是,您应该检查之前至少有 180 字节的文件。您应该知道这些操作中的 any 可能会失败,因此您应该检查流的状态,在每个单个操作之后或至少在其中几个操作之后(因此至少在调整大小之前你的向量 PV
)。旁注:如果流已经处于失败状态,则每个后续操作也将失败,除非您 clear()
之前的错误状态。
std::vector<double> PV (size / sizeof(double));
呃,我觉得很奇怪...你从偏移量 180 开始,所以我认为你应该在除法之前减去;一世。即:
size_t size = ...;
if(size < 180) // bad file!
{
// throw or whatever appropriate
}
size -= 180;
// go on...
如果没有此修复,下一行将 总是 导致抛出以下异常,因为您会读取超出文件末尾的内容(请记住,您是从文件开始读取的偏移 180!):
if (!is.read((char*)&PV[0], size))
但更喜欢 C++ 风格的转换:
if (!is.read(reinterpret_cast<char*>(PV.data()), size))
您会很快发现您需要 reinterpret_cast
,有时是合适的,但在大多数情况下,如果您考虑使用它,至少应该敲响警钟,它只是隐藏了一些更深层次的问题,例如未定义的行为。 PV.data()
自 C++11 以来就存在并且比 &PV[0]
更容易阅读,但两者是等价的。
但是,我们现在还有一个不同的问题:
虽然该标准没有说明任何关于精度甚至格式的信息 ("The value representation of floating-point types is implementation-defined."),但在您的系统上,double 很可能是 64 位 IEEE754 数据类型。您真的确定数据正是以这种格式存储的吗?只有这样,这个 才能 工作,但是,它是非常危险的,文件生产者和消费者可能会说不同的语言,并且很可能你得到错误的输入...
现在承认,我根本不是matlab专家,但你的下面这行让我强烈怀疑上面的输入格式是否适用:
PV = fread(fid, [A*3 B+2], 'float32');
^^
最后,你已经读取你的数据已经在if
子句中,所以放弃这个第二行,它只会产生另一个失败...
如果现在数据不是以二进制形式存储,而是以人类可读的格式存储,您可以读取如下值:
std::vector<double> pv; // prefer lower camel case variable names
pv.reserve(size/sizeof(double)); // just using as a size hint;
// we can't deduce number of entries
// from file length exactly any more
double v;
while(is >> v)
{
pv.push_back(v);
}
if(!v.eof())
{
// we did not consume the whole file, so we must
// assume that some input error occurred!
// -> appropriate error handling (throw?)
}
慢慢走到尽头:
// std::vector<double> Result1 =
// std::vector<double> Result2 =
// std::vector<double> Result3 =
注释掉;对,你不需要它们,你已经在结果 vector/array 中有了它们,我。 e. result[0]
、result[1]
和 result[2]
...
根据需要调整它们的大小(或保留)以将结果数据放入并继续。
很抱歉,我现在不太清楚你的 matlab 计算是做什么的,我也不会为了这个答案而学习 matlab——不过,有了上面的提示,你可能会相处得很好。进一步提示:您不能将 vectors/arrays 作为一个整体相互相乘或直接与标量相乘;您必须在循环中分别为每个元素执行此操作。您可能会考虑 std::valarray an interesting alternative, though. Additionally, you might find some interesting stuff in the algorithm library,尤其是在 "numeric operations" 部分下。如果您对这些不满意,请随时提出另一个问题...