簡體   English   中英

計算 POD 結構向量中所有數據成員的平均值

[英]Calculate average of all data members in a vector of POD struct

我有一個提供 3 種不同讀數的傳感器。 我想讀取傳感器 X 次,然后獲取所有讀數的平均值:

#define NUM_DATA ((int)1000);

struct Data {
    int x;
    int y;
    int z;
}

Data getAverageData() {
    
    static std::vector<Data> vecData(NUM_DATA); // Vector for sensor data
    vecData.clear();
    
    for(int i = 0; i < NUM_DATA; i++) {
        int x = sensorGetX(); // from sensor
        int y = sensorGetY(); // from sensor
        int z = sensorGetZ(); // from sensor
        
        vecData[i] = {x, y, z};
    }
        
    // I am stuck here!!!
    Data average = std::accumulate(vecData.begin(), vecData.end(), 0.0,
                                     [&](int sum, Data d) {
            return sum + d.x;
        });    

    return average;
}

Data結構既用於將數據保存在向量中,也用於平均值本身。 我想保持這種狀態。 我當然知道要以老式的方式來做,但我希望我的代碼看起來很聰明,並且我想使用 c++11 或 c++17 必須提供的最新功能。

constexpr unsigned int num_data = 1000;

struct Data {
    int x;
    int y;
    int z;
}

Data getAverageData() {
    
    Data vecData_temp = {0, 0, 0};

    for(size_t i = 0; i < num_data; ++i) {
        vecData_temp.x += sensorGetX();
        vecData_temp.y += sensorGetY();
        vecData_temp.z += sensorGetZ();
    }

    vecData_temp.x /= num_data;
    vecData_temp.y /= num_data;
    vecData_temp.z /= num_data; 

    return vecData_temp;
}

在這種情況下,我看不到創建向量的意義。 嘗試了這個輕量級代碼,只創建了一個局部變量。

Joonroo Taugh 的回答很好; 但是,如果您想使用最新的c++17功能,我會像這樣使用 go ,無論如何您幾乎都正確。

唯一的問題是您沒有正確設置您的收藏:

  • 使用push_back而不是使用下標運算符;
  • 使用reserve一次性分配一個數據塊,否則push_back會在容量用完時分配(每超過一次push_back只會多分配1.5倍的容量);
  • 在使用static集合時,使用clear可以很好地丟棄舊數據。

注意:我添加了一些輔助運算符重載,以使平均計算看起來更數學化並且更易於理解。

我還會考慮傳入要填充的vector引用或從 function 返回本地向量實例作為std::pair<Data, std::vector<Data>的一部分,以便您可以跟蹤最后的X值(這可能是它自己的論點,取決於你)。

#include <numeric>
#include <vector>

//Default-construct members so they are not uninitialized.
struct Data {
    float x{};
    float y{};
    float z{};
}

Data operator/(const Data& lhs, float scalar) {
    return Data{lhs.x / scalar, lhs.y / scalar, lhs.z / scalar};
}

Data operator+(const Data& lhs, const Data& rhs) {
    return Data{x + rhs.x, y + rhs.y, z + rhs.z};
}

Data getAverageData() {
    constexpr std::size_t num_data{1000u}; //This could be an argument into the function...
    static std::vector<Data> vecData{};

    //Clear any data from the previous calculation.
    //Does not affect capacity.
    vecData.clear();
    vecData.reserve(num_data); //Reserve space all at once so push_back doesn't allocate.

    for(auto i = std::size_t{0u}; i < num_data; ++i) {
        vecData.emplace_back(sensorGetX(), sensorGetY(), sensorGetZ());
    }

    const auto average = std::accumulate(std::cbegin(vecData), std::cend(vecData), Data{},
    [&](Data sum, Data d) {
        return sum + (d / static_cast<float>(vecData.size()));
    });
    return average;
}

之后,如果您不想將結果向量用作直方圖,則可以完全按照 Joonroo 的建議進行操作,只需使用臨時變量即可。 不過,使用運算符重載會更容易:

#include <vector>

//Default-construct members so they are not uninitialized.
struct Data {
    float x{};
    float y{};
    float z{};
    Data& operator+=(const Data& rhs) {
        x += rhs.x;
        y += rhs.y;
        z += rhs.z;
        return *this;
    }
    Data& operator/=(float scalar) {
        x /= scalar;
        y /= scalar;
        z /= scalar;
        return *this;
    }
}

Data operator/(const Data& lhs, float scalar) {
    return Data{lhs.x / scalar, lhs.y / scalar, lhs.z / scalar};
}

Data operator+(const Data& lhs, const Data& rhs) {
    return Data{x + rhs.x, y + rhs.y, z + rhs.z};
}

Data getAverageData(std::size_t sensor_read_count = 1000) {
    Data average{};
    for(auto i = std::size_t{0u}; i < sensor_read_count; ++i) {
        average += Data{sensorGetX(),sensorGetY(),sensorGetZ()};
    }
    average /= static_cast<float>(sensor_read_count);
    return average;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM