CおよびC++で32ビット浮動小数点変数をシリアル化してマイクロコントローラとの間でやりとりするポータブルな方法を見つけることに苦労しています。あまりにも多くの労力を費やすことなく、シリアライゼーション/デシリアライゼーションを他の言語からも行うことができるように、フォーマットを十分に定義しておきたい。関連した質問は以下のとおりです。floatを32ビット整数としてシリアル化する移植可能な方法
Portability of binary serialization of double/float type in C++
Serialize double and float with C
c++ portable conversion of long to double
私はほとんどの場合、はフロート表現が同じであるため、組合/ memcpyのはうまく動作します型キャストが、私ことを知っていますもう少しコントロールと心の部分を持っていることを好むだろう。私は今のところ思い付いたことは以下の通りです:
void serialize_float32(uint8_t* buffer, float number, int32_t *index) {
int e = 0;
float sig = frexpf(number, &e);
float sig_abs = fabsf(sig);
uint32_t sig_i = 0;
if (sig_abs >= 0.5) {
sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
e += 126;
}
uint32_t res = ((e & 0xFF) << 23) | (sig_i & 0x7FFFFF);
if (sig < 0) {
res |= 1 << 31;
}
buffer[(*index)++] = (res >> 24) & 0xFF;
buffer[(*index)++] = (res >> 16) & 0xFF;
buffer[(*index)++] = (res >> 8) & 0xFF;
buffer[(*index)++] = res & 0xFF;
}
と
float deserialize_float32(const uint8_t *buffer, int32_t *index) {
uint32_t res = ((uint32_t) buffer[*index]) << 24 |
((uint32_t) buffer[*index + 1]) << 16 |
((uint32_t) buffer[*index + 2]) << 8 |
((uint32_t) buffer[*index + 3]);
*index += 4;
int e = (res >> 23) & 0xFF;
uint32_t sig_i = res & 0x7FFFFF;
bool neg = res & (1 << 31);
float sig = 0.0;
if (e != 0 || sig_i != 0) {
sig = (float)sig_i/(8388608.0 * 2.0) + 0.5;
e -= 126;
}
if (neg) {
sig = -sig;
}
return ldexpf(sig, e);
}
私がしようとしたfrexpとldexp機能は、この目的のために作られているように見えるが、場合には、それらは使用できません。
float frexpf_slow(float f, int *e) {
if (f == 0.0) {
*e = 0;
return 0.0;
}
*e = ceil(log2f(fabsf(f)));
float res = f/powf(2.0, (float)*e);
// Make sure that the magnitude stays below 1 so that no overflow occurs
// during serialization. This seems to be required after doing some manual
// testing.
if (res >= 1.0) {
res -= 0.5;
*e += 1;
}
if (res <= -1.0) {
res += 0.5;
*e += 1;
}
return res;
}
と
:共通している機能を使用して手動でだけでなく、それらを実装しますfloat ldexpf_slow(float f, int e) {
return f * powf(2.0, (float)e);
}
私が検討してきたことの1つは、8388608(2^23)か8388607(2^23-1)を乗算器として使用するかどうかです。 frexpは1より小さい値を返し、いくつかの実験の後には実際の浮動小数点でビット精度の結果が得られ、このオーバーフローが発生するコーナーケースを見つけることができなかったようです。しかしそれは異なるコンパイラ/システムでは当てはまらないかもしれません。これが問題になる可能性がある場合は、精度を落とす小さな乗算器も私にとっては問題ありません。私はこれがInfやNaNを処理しないことを知っていますが、今のところこれは必須条件ではありません。
最後に、私の質問です:これは合理的なアプローチのようですか、それとも移植性の問題がある複雑なソリューションを作成していますか?フロートを仮定
のいずれかを使用する必要があります。短い答え:例えばgoogle protobufのようなデシリアライズライブラリ/ツールを使用しない限り、移植可能な方法では実際にはできません。 –
私が提示したアプローチの問題点は何ですか?私が普段読んでいるのは、浮動小数点表現がすべてのシステムで同じであることを保証できないということです。そのため、浮動小数点の内部表現が何であるかにかかわらず常に同じものを生成しようとします。 –
_Endianess_のいずれかの問題の名前を指定します。 –