2

加算および乗算から返された浮動小数点値が無効になるという問題があります。

背景: Visual Studio マルチスレッド環境で Speex を使用しています。そして、ある時点で、通常、オーディオのエンコードとデコードの 1 ~ 2 分後、デコードされた信号は完全に Nan になります。私の問題は、このスレッド ( Windows での Speex、オーディオの切断) で説明されているものと同じだと思いますが、この問題をもう少し深く掘り下げました。

状況: libspeex の一部を変更して、デバッグ コードを配置しました。これが私が持っているものです (ここでいくつかのマクロを展開しました。いくつかの部分が冗長であることはわかっています)。

float *mem, *den;     // Arrays of finite float values
float nyi;      // finite float value.
float a1, a2;   // debug test variables.

...

if (!_finite(mem[j]) || !_finite(mem[j+1]))
    printf("Nan\n");       // Does not reach this

a1     = ((mem[j+1])+(float)(den[j])*(float)(nyi));   // a1 == expected value
mem[j] = ((mem[j+1])+(float)(den[j])*(float)(nyi));   // mem[j] == -1.#IND
a2     = ((mem[j+1])+(float)(den[j])*(float)(nyi));   // a2 == expected value

if (!_finite(mem[j]) || !_finite(mem[j+1]))
    printf("Nan\n");          // Program reach this and stops at breakpoint

最初の奇妙な動作は、a1a2が正しい値を計算するのに対し、mem[j]は計算しないことです。2番目の奇妙なこと: mem[j]ステートメントへの影響を再実行しようとすると(予期しない結果につながる可能性があることはわかっていますが、それでもデバッグ目的のヒントが得られます)、mem[j]に影響する値は次のようになります。期待値: a1 および a2 と同じ。

私は明らかなことを確認しました:

  • このコード部分はミューテックスで保護されています。別のスレッドがメモリを破損する可能性はありません。
  • すべての float 値は有効で有限であり、加算と乗算の結果は float の範囲内にある必要があります。
  • すべての配列インデックスは、それぞれの配列の範囲内にあります。

他のスレッドが実行されていない場合、問題は発生しないようです。

  • このスレッド: オーディオ デコード スレッド。
  • オーディオ エンコーディング スレッド。
  • いくつかのネットワーク ソケット スレッド...

これは大きなソフトウェアの一部ですが、デコード部分は適切なミューテックスによって残りから保護されています。

そのため、float 計算の途中でコンテキスト スイッチが発生し、その後コンテキストの復元に失敗したように見えます。しかし、何か悪いことが起こる可能性があるとは信じがたいです。

マルチスレッドで使用した場合の浮動小数点の不一致について聞いたことがありますが、それは最下位部分にのみ影響し、Nan 値を生成しないはずです。

誰かがそのような行動を見たことがありますか?どのように解決しましたか?

4

1 に答える 1

2

質問:

  • 余分なキャストはどうしたの?
  • den[j]との値は何nyiですか?

それらはさておき、合理的な可能性は、同じスレッドでの別の計算が浮動小数点スタックをオーバーフローしたか、MMX命令を使用したが、emms制御を生成する前に命令を発行できなかったことです(これらの条件のいずれかにより、他の点では問題のない浮動小数点計算が発生しますNaN結果を生成します)。障害状態のx87ステータスワードを調べて、これらの可能性を確認または除外することから始めます。

複数のスレッドがないと問題が発生しないという事実により、この説明の可能性はやや低くなりますが、破損したx87状態は、「他の方法では説明できない」NaNの最も一般的な原因であり、最初に除外する必要があります。

于 2012-07-27T14:24:03.913 に答える