【问题标题】:How to initialize double matrix with NaN element?如何用 NaN 元素初始化双矩阵?
【发布时间】:2018-11-12 13:38:28
【问题描述】:

在我的代码中,我有一个这样的双精度矩阵:

double * * matrix=new double * [10];
for(int i=0;i<10;i++) 
    matrix[i]=new double[10];

当我初始化它时,我想在这个矩阵的每个单元格中都有 NaN 值,是否可以自动执行或唯一的解决方案是:

for(int i=0;i<10;i++)
    for(int j=0;j<10;j++)
        matrix[i][j]=nan("");

是否可以推断当矩阵将costruct时,它不使用插入的double的默认构造函数,对于每个matrix[i][j],0.0值但插入nan(“”)?

【问题讨论】:

  • 请不要使用这样的低级指针进行编码。 godbolt.org/g/qMVXHH
  • 这不是C...请使用std::vector...
  • @samuelnj 为什么不是 c (++)?为什么我不能使用低级指针?
  • 你不应该使用低级指针,因为它们很容易产生错误,而且在 C++ 中有更好的替代方案。

标签: c++ c++11 nan


【解决方案1】:

double 没有默认构造函数,即double 值默认未初始化。

为避免显式实现循环,您可以使用std::vector

#include <vector>
...
std::vector<std::vector<double>> matrix(10, std::vector<double>(10, nan("")));

或:

#include <vector>
using namespace std;
...
vector<vector<double>> matrix(10, vector<double>(10, nan("")));

【讨论】:

    【解决方案2】:

    首先,强烈避免自己在 C++ 中使用原始指针 - 这几乎总是一个坏主意。如果没有适合的容器类,请使用std::unique_ptr。所以你的代码变成了:

    auto matrix = std::make_unique<double* []>(10);
    for(int i=0;i<10;i++)  {
        matrix.get()[i]= std::make_unique<double []>(10);
    }
    

    这段代码仍然不是你想要的。使用对new 的 N 次调用或向量的 n 次构造来创建 NxN 矩阵通常不是一个好主意。对 NxN 双精度进行一次分配,然后将其包装在支持 2 参数方括号运算符的类 MyMatrix 中,即

    template <typename T>
    class MyMatrix { 
       // etc. etc
       double const T& operator[](size_type i, size_type j) const { return data_[i*n + j]; }
       double T& operator[](size_type i, size_type j) { return data_[i*n + j]; }
    }
    

    或(不推荐)将指针指向单一分配区域:

    size_t n = 10;
    auto matrix_data = std::make_unique<double []>(n * n);
    auto matrix = std::make_unique<double* []>(n);
    for(int i=0;i<10;i++)  {
        matrix.get()[i] = matrix_data.get() + i * n;
    }
    

    在每种情况下,您以后都可以在任何循环之外使用std::fill 将所有矩阵值设置为 NaN。

    上面的最后一个示例也可以转换为使用向量(如果您不使用自己的类,这可能比仅使用原始指针更好):

    size_t n = 10;
    auto matrix_data = std::vector<double>(n * n);
    auto matrix = std::vector<double*>(n);
    for(auto& row : matrix) {
        auto row_index = std::dist(row, matrix.begin());
        row = &matrix_data[row_index * n];
    }
    

    再次,我不建议这样做 - 它仍然是一种类似 C 的方式来启用 my_matrix[i][j] 语法,而使用包装类可以让您获得 my_matrix[i,j] 而无需额外存储,初始化为 NaN 或其他值 (在构造函数中),并且每次访问它时都不会跟随两个指针。

    【讨论】:

      【解决方案3】:

      如果您想使用静态大小的数组,最好使用std::array。为了更容易使用多维std::array,您可以使用模板别名

      template <class T, size_t ROW, size_t COL>
      using Matrix = std::array<std::array<T, COL>, ROW>;
      

      您可以使用std::array::fill 设置矩阵中的值,例如

      Matrix<double, 3, 4> m = {};
      m.fill(42.0);
      

      您还可以创建一个使用默认值初始化的编译时常量矩阵对象,以使用简单的constexprfunction 在运行时跳过初始化。

      template<typename T, size_t R, size_t C>
      constexpr auto makeArray(T&& x) {
          Matrix<T,R,C> m = {};
          for(size_t i=0; i != R; ++i) {
              for(size_t j=0; j != C; ++j) {
                  m[i][j] = std::forward<T>(x);
              }
          }
          return m;
      }
      
      auto constexpr m = makeArray<double, 3,4>(23.42);
      

      我将重复给出的建议,即更喜欢 C++ 构造而不是 C 构造。它们更安全,恕我直言,几乎总是更方便使用,例如将std::array 对象作为参数传递与任何其他对象没有区别。如果您来自 C 背景并且没有进一步的 C++ 经验,我建议您阅读一些不首先介绍 C 的教程文本,例如The Tour of C++,

      【讨论】:

        猜你喜欢
        • 2019-11-29
        • 2020-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多