2017-01-13 13 views
0

BigEndian書式のQbyteArray変数を持っています 最小プロセスでその変数から浮動小数点数型配列を取得したいとします。 最も速い方法は何ですか?QByteArrayからbigendian形式の浮動小数点配列を効率的に取得する

私は次のコードを使用していますが、それは効率的ではないと思います。

QByteArray::mid()に呼び出しを削除し、余分なコピー・オン・ライトを防ぐためにのみconst機能を使用し、

float getValue(QByteArray dataBytes, int i){  
    QByteArray data = dataBytes.mid(i*4, 4); 
    qint32 level = qFromBigEndian<qint32>((uchar*)data.data()); 
    float result = level*1.0; 
} 

float *f = new float[20]; 
for (int i=0;i<20;i++){ 
    f[i] = getValue(myDataBytes, i); 
} 
+0

質問1:エンコードされた数値の整数ですか?質問2:ポータブルにしたいですか? –

+0

ちょうどチェック: 'QByteArray'は' qint32'を含み、各BigEndian整数を通常のfloatに変換したいですか?その精度が失われることに注意してください。可能なすべての 'qint32'を表すには' double'が必要です。 – MSalters

答えて

1

なぜイテレータを作成せずにstd::vectorをビルドしますか?効率と完全な安全性の損失ん:godbolt上

#include <cstdint> 
#include <algorithm> 
#include <vector> 
#include <iterator> 

// simulate types 
using qint32 = std::int32_t; 

struct QByteArray { 
    QByteArray mid(int, int); 
    const std::uint8_t* data() const; 
    const std::size_t* size() const; 
}; 

// simulate functions 
template<class T> T qFromBigEndian(const std::uint8_t*); 

// iterator to convert big endian byte streams to ints 
struct big_endian_ints_iterator 
    : std::iterator<std::forward_iterator_tag, std::int32_t> 
{ 

    big_endian_ints_iterator(const std::uint8_t * p) : ptr_(p) {} 

    big_endian_ints_iterator& operator+=(std::size_t i) { 
    ptr_ += 4 * i; 
    return *this; 
    } 

    big_endian_ints_iterator& operator++() { 
    ptr_ += 4; 
    return *this; 
    } 

    big_endian_ints_iterator operator++(int) { 
    auto tmp = *this; 
    ptr_ += 4; 
    return tmp; 
    } 

    value_type operator*() const { 
    return qFromBigEndian<std::int32_t>(ptr_); 
    } 

    bool operator!=(const big_endian_ints_iterator& r) const { 
    return r.ptr_ != ptr_; 
    } 

    bool operator==(const big_endian_ints_iterator& r) const { 
    return r.ptr_ == ptr_; 
    } 

    const std::uint8_t* ptr_; 
}; 

big_endian_ints_iterator operator+(big_endian_ints_iterator l, std::size_t r) 
{ 
    return l += r; 
} 

std::vector<float> test(QByteArray const& myDataBytes) 
{ 
    auto first = big_endian_ints_iterator(myDataBytes.data()); 
    std::vector<float> f(first, first + 20); 
    return f; 
} 

証明:https://godbolt.org/g/PG3H2V

+0

これはどのように「完全な安全性」ですか?あなたのコードはポインタ演算のみを行い、問題のコードよりも安全ではありません。 ' std :: vector f(最初、最初+ 21);を試してください。そして' _ptr'はQByteArrayバッファの後ろを指しています。おそらく未割り当てのメモリにあります。 –

+0

@BenjaminT私は、フロートのベクトルの管理の面で安全を意味します。私はQByteArrayに慣れていませんが、ベクターを初期化する前にその長さをチェックする方法が必要であると確信しています。 –

1

クイック答えを助けてください。それ以外に、私はあなたがもっと効率的になるとは思わない、多分関数をインライン化するかもしれない。

inline float getValue(const QByteArray &dataBytes, int i){ 
    const qint32 level = qFromBigEndian<qint32>(&static_cast<const qint32 *>(dataBytes.constData())[i]); 
    return level*1.0; 
} 
関連する問題