【问题标题】:Translating Matlab code of vector creation to C++将向量创建的 Matlab 代码翻译成 C++
【发布时间】:2018-02-22 15:36:04
【问题描述】:

我有这个 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 个大小为 BxA 的填充向量并输入 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];  

This question 对我来说确实有意义,但仍然不明白如何重写这部分:(1:3:3*A, 2:B+1) in C++?

注意:
-我仅限于使用标准库(没有 boost、mmap 等)。
-我检查了关于冒号的 Mathwork 文档(但仍然无法理解如何实现它)。

【问题讨论】:

  • 与其尝试从一种语言逐行翻译到 C++ ,不如从高级术语中考虑该表达式应该做什么。不管它应该做什么,用 C++ 编写等效的代码。
  • 1:3:3*A = [1, 1+3, 1+2*3, ...] 直到 3*a; 2:B+1 = [2 B+1] 但是所有这些对我来说没有意义。 (或者我错过了什么)
  • 如果你试图写的东西对你没有意义,你就不能用 C++ 写东西。这听起来更像是基于 MatLab 的问题,而不是 C++ 问题。

标签: c++ matlab vector colon


【解决方案1】:

由于向量的结果大小是固定的,我宁愿使用 std::array:

std::array<std::vector<double>, 3> result;

也不再调整大小,反正看起来会简单得多:

//result.resize(B, std::vector<double>(A));
result.resize(3);

通过这一行,您的外部向量现在正好包含三个向量 - 每个向量都是空的 - 就像使用数组方法一样。无论您最终选择哪个,都需要显式调整内部向量的大小。不过,我们稍后再讨论。

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 个字节的文件。您应该知道 任何 这些操作都可能会失败,因此您应该检查流的状态,无论是在每个单个操作之后还是至少在其中几个操作之后(所以至少在调整矢量大小之前 @ 987654326@)。旁注:如果流已经处于失败状态,那么每个后续操作也会失败,除非你clear()之前的错误状态。

std::vector<double> PV (size / sizeof(double));

呃,对我来说看起来很奇怪......你从偏移量 180 开始,所以我假设你应该在除法之前减去;一世。 e.:

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 开始就存在,并且比 &amp;PV[0] 更容易阅读,但两者是等价的。

但是,我们现在还有一个不同的问题:

虽然标准没有说明任何关于精度甚至格式的内容(“浮点类型的值表示是实现定义的。”),但很可能在您的系统上 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 = 

注释掉;对,你不需要它们,你已经在结果向量/数组中有了它们,i。 e. result[0]result[1]result[2]...

根据需要调整它们的大小(或保留)以将结果数据放入并继续。

很抱歉,我现在并不真正了解您的 matlab 计算是做什么的,并且我不会为这个答案学习 matlab - 不过,有了上面的提示,您可能会相处得很好。只是进一步的提示:您不能将向量/数组作为一个整体相乘或直接与标量相乘;您必须在循环中分别为每个元素执行此操作。不过,您可能会认为std::valarray 是一个有趣的选择。此外,您可能会在algorithm library 中找到一些有趣的东西,尤其是在“数字运算”部分下。如果您不了解这些,请随时问另一个问题...

【讨论】:

  • 感谢您如此详细的回复。 std::valarray 看起来非常适合我的目标!题外话:我认为我们可以使用 std::inner_product 来乘向量,不是吗?
  • @SerhiiS。第一:确保清楚地区分 std::vector 和数学向量,它们是完全独立的概念(除了你可以通过前者来表示后者......)。 std::inner_product 为您提供两个数学向量的标量积...
猜你喜欢
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 2016-08-04
  • 2014-01-06
  • 1970-01-01
相关资源
最近更新 更多