加算および乗算から返された浮動小数点値が無効になるという問題があります。
背景: 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
最初の奇妙な動作は、a1とa2が正しい値を計算するのに対し、mem[j]は計算しないことです。2番目の奇妙なこと: mem[j]ステートメントへの影響を再実行しようとすると(予期しない結果につながる可能性があることはわかっていますが、それでもデバッグ目的のヒントが得られます)、mem[j]に影響する値は次のようになります。期待値: a1 および a2 と同じ。
私は明らかなことを確認しました:
- このコード部分はミューテックスで保護されています。別のスレッドがメモリを破損する可能性はありません。
- すべての float 値は有効で有限であり、加算と乗算の結果は float の範囲内にある必要があります。
- すべての配列インデックスは、それぞれの配列の範囲内にあります。
他のスレッドが実行されていない場合、問題は発生しないようです。
- このスレッド: オーディオ デコード スレッド。
- オーディオ エンコーディング スレッド。
- いくつかのネットワーク ソケット スレッド...
これは大きなソフトウェアの一部ですが、デコード部分は適切なミューテックスによって残りから保護されています。
そのため、float 計算の途中でコンテキスト スイッチが発生し、その後コンテキストの復元に失敗したように見えます。しかし、何か悪いことが起こる可能性があるとは信じがたいです。
マルチスレッドで使用した場合の浮動小数点の不一致について聞いたことがありますが、それは最下位部分にのみ影響し、Nan 値を生成しないはずです。
誰かがそのような行動を見たことがありますか?どのように解決しましたか?