1

いくつかの float をテキスト ファイルに書き込み、CRC32 チェックサムを格納する必要があります。次に、フロートをテキスト ファイルから読み戻すときに、チェックサムを再計算し、ファイルを保存するときに以前に計算されたものと比較します。私の問題は、チェックサムが時々失敗することです。これは、同じ浮動小数点数を異なるビット パターンで表すことができるためです。完全を期すために、次の段落でコードを要約します。

この質問を読んだ後に見つけたこのCRC32アルゴリズムを採用しました。外観は次のとおりです。

uint32_t updC32(uint32_t octet, uint32_t crc) {
    return CRC32Tab[(crc ^ octet) & 0xFF] ^ (crc >> 8);
}

template <typename T>
uint32_t updateCRC32(T s, uint32_t crc) {
    const char* buf = reinterpret_cast<const char*>(&s);
    size_t len = sizeof(T);

    for (; len; --len, ++buf)
        crc = updC32(static_cast<uint32_t>(*buf), crc);
    return crc;
}

CRC32Tab上記のリンクされたファイルの大きな配列とまったく同じ値が含まれています。

これは、フロートをファイルに書き込んでチェックサムを計算する方法の簡略版です。

float x, y, z;

// set them to some values

uint32_t crc = 0xFFFFFFFF;
crc = Utility::updateCRC32(x, crc);
crc = Utility::updateCRC32(y, crc);
crc = Utility::updateCRC32(z, crc);
const uint32_t actualCrc = ~crc;

// stream is a FILE pointer, and I don't mind the scientific representation
fprintf(stream, " ( %g %g %g )", x, y, z);
fprintf(stream, " CRC %u\n", actualCrc);

次のように、ファイルから値を読み戻します。ファイルにはより複雑な構文があり、解析する必要があるため、実際にはさらに多くの作業が必要になりますが、 がgetNextFloat()以前に記述された各 float のテキスト表現を返すと仮定しましょう。

float x = std::atof(getNextFloat());
float y = std::atof(getNextFloat());
float z = std::atof(getNextFloat());

uint32_t crc = 0xFFFFFFFF;
crc = Utility::updateCRC32(x, crc);
crc = Utility::updateCRC32(y, crc);
crc = Utility::updateCRC32(z, crc);
const uint32_t actualCrc = ~crc;

const uint32_t fileCrc = // read the CRC from the file
assert(fileCrc == actualCrc); // fails often, but not always

この問題の原因は、std::atof が、ファイルから読み取られた文字列にエンコードされた浮動小数点数の異なるビット表現を、その文字列をファイルに書き込むために使用された浮動小数点数のビット表現とは異なることです。

だから、私の質問は次のとおりです。文字列自体をチェックサムする以外に、テキスト表現を介して往復するフロートをチェックサムするという私の目標を達成する別の方法はありますか?

読んでくれてありがとう!

4

5 に答える 5

1

テキスト ファイルが人間が読める形式である必要がない場合は、代わりに16 進数の float リテラルを使用してください。これらは正確であるため、テキスト値とメモリ内の値が異なるというこの問題は発生しません。

于 2013-03-15T10:39:29.590 に答える
1

問題の原因は、あなたのコメントから明らかです。

私が完全に間違っていなければ、ここでは丸めは行われていません。%g指定子は、数値を正確に表す最短の文字列表現を選択します。

これは正しくありません。精度が指定されていない場合、デフォルトは 6 になり、ほとんどの浮動小数点入力に対して丸めが確実に行われます。

人間が読めるラウンドトリップ可能な形式が必要な場合%aは、断然最良の選択です。それができない場合は、少なくとも 9 の精度を指定する必要があります (floatシステムが IEEE-754 単精度であると仮定します)。

標準では、出力する方法や必要があるかどうかが指定されていないため、NaN エンコーディングによってつまずく可能性があります。

于 2013-03-15T11:00:09.797 に答える
0

あなたの CRC アルゴリズムは、単一の値に対して複数のバイナリ表現を持つ型に対して欠陥があります。IEEE 754 には、+0.0 と -0.0 という 2 つの 0.0 の表現があります。NaN などのその他の非有限値も問題になる可能性があります。

于 2013-03-15T10:54:46.923 に答える
0

標準ライブラリの浮動小数点数からテキストへの変換とテキストから浮動小数点数への変換が適切な丸めを行う場合、Infs と NaN も持っていない限り、float->text->float のラウンドトリップがロスレスになるのに十分な有効桁数が必要です。無限大または NaN には複数の表現があるため、必ずしもビットパターンを保存する必要はありません。IEEE-754 の場合、64 ビット倍精度の有効桁数 17 桁で、実際の値に関してラウンドトリップを無損失にするのに十分です。

于 2013-03-15T10:45:13.100 に答える
0

CRC を更新する前に数値を正規化してもよいでしょうか? したがって、保存中に数値の一時的な文字列バージョンを取得し (sprintf またはシリアル化の形式に一致するものを使用)、この文字列を数値に変換し、この結果を使用して CRC を更新します。このようにして、CRC がデシリアライズされた値と一致することがわかります。

于 2013-03-15T11:14:14.833 に答える