0

プランクの法則に従って、次のように黒体放射の実装に取り​​組んできました。

double BlackBody(double T, double wavelength) {
  wavelength /= 1e9; // pre-scale wavelength to meters

  static const double h = 6.62606957e-34; // Planck constant
  static const double c = 299792458.0; // speed of light in vacuum
  static const double k = 1.3806488e-23; // Boltzmann constant

  double exparg = h*c / (k*wavelength*T);
  double exppart = std::exp(exparg) - 1.0;
  double constpart = (2.0*h*c*c);
  double powpart = pow(wavelength, -5.0);
  double v = constpart * powpart / exppart;
  return v;
}

float[max-min+1] 配列があり、static const int max=780、static const int min = 380 です。単に配列を反復処理し、BlackBody が波長に対して与えるものを入力します (波長 = array-インデックス + 分)。IntensitySpectrum::BlackBody はこの反復を実行しますが、min と max は両方とも静的メンバー変数であり、配列も IntensitySpectrum 内にあります。

IntensitySpectrum spectrum;

Vec3 rgb = spectrum.ToRGB();
rgb /= std::max(rgb.x, std::max(rgb.y, rgb.z));
for (int xc = 0; xc < grapher.GetWidth(); xc++) {
  if (xc % 10 == 0) {
    spectrum.BlackBody(200.f + xc * 200.f);
    spectrum.Scale(1.0f / 1e+14f);
    rgb = spectrum.ToRGB();
    rgb /= std::max(rgb.x, std::max(rgb.y, rgb.z));
  }
  for (int yc = 20; yc < 40; yc++) {
    grapher(xc, yc) = grapher.FloatToUint(rgb.x, rgb.y, rgb.z);
  }
}

問題は、線スペクトル.BlackBody() が配列の 0 番目の要素を NaN に設定し、0 番目のみを設定することです。また、最初の反復では発生しませんが、xc>=10 である以降の反復ではすべて発生します。

VS デバッガーからのテキスト: Spectrum = {intensity=0x009bec50 {-1.#IND0000, 520718784., 537559104., 554832896., 572547904., 590712128., 609333504., ...} }

エラーを追跡したところ、::BlackBody() 関数の exppart が NaN になり、引数が 2.0 に近いにもかかわらず、基本的に exp() は NaN を返すため、明らかにオーバーフローしません。ただし、配列インデックス 0 のみです。残りの 400 インデックスに対して魔法のように機能し始めます。

メモリオーバーランがそのようなことを引き起こす可能性があることは知っています。そのため、メモリ処理を再確認しました。私は別の自作ライブラリから Vec3 をリンクしていますが、これははるかに大きく、エラーが含まれている可能性がありますが、Vec3 から使用するものはメモリとは何の関係もありません。

何時間も経った後、私は完全に無知です。他に何がこれを引き起こす可能性がありますか? オプティマイザまたは WINAPI が私を騙していませんか? (ええと、はい、プログラムは WINAPI でウィンドウを作成し、WM_PAINT で私のコードを呼び出すほぼ空の WndProc を使用します。)

事前にご協力いただきありがとうございます。

わかりづらくてすみません。これはレイアウトです:

// member
class IntensitySpectrum {
public:
    void BlackBody(float temperature) {
        // ...
        this->intensity[i] = ::BlackBody(temperature, wavelength(i));
        // ...
    }
private:
    static const int min = 380;
    static const int max = 780;
    float intensity[max-min+1];
}

// global
double BlackBody(double T, double wavelength);
4

2 に答える 2

1

MSVC 2013 を使用している場合、考えられる説明の 1 つは、float 無限大を int に変換しようとしているコードがどこかにあるということです。これが発生すると、MSVC 2013 のバグにより、x87 FPU スタックで不均衡なプッシュが発生します。そのバグを 8 回トリガーすると、FPU スタックが完全にいっぱいになり、その後値をプッシュしようとすると ('exp()' の呼び出しなど)、'無効な操作' が発生し、不定値 (1.#IND など) が返されます。 . SSE2 浮動小数点命令を使用してコンパイルしている場合でも、呼び出し規則では浮動小数点の戻り値が FPU スタックの一番上に返されるように指示されているため、このバグは依然として影響を受ける可能性があることに注意してください。

これが問題であるかどうかを確認するには、「exp()」への不正な呼び出しの直前に FPU レジスタを調べます。TAGS レジスタがすべてゼロの場合、FPU スタックがいっぱいです。

MS は、これは MSVC 2013 の更新 2 で修正されると主張しています。

于 2014-04-28T20:33:57.137 に答える
-1

次の関数呼び出しには、1 つのパラメーターしかありません。

spectrum.BlackBody(200.f + xc * 200.f);

したがって、定義した関数を呼び出すことはできません

double BlackBody(double T, double wavelength)

実装を見ると、::BlackBody0 除算エラーがどこかにあるはずです。

于 2014-01-21T21:04:31.320 に答える