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 调试器的文本:频谱 = {intensity=0x009bec50 {-1.#IND0000, 520718784., 537559104., 554832896., 572547904., 590712128., 609333504., ...} }

我跟踪错误, ::BlackBody() 函数中的 exppart 变为 NaN,基本上 exp() 返回 NaN,即使它的参数接近 2.0,所以绝对不会溢出。但仅适用于数组索引 0。它神奇地开始为其余 400 个索引工作。

我知道内存溢出可能会导致这样的事情。这就是为什么我仔细检查了我的内存处理。我正在从另一个自制的库中链接 Vec3,该库要大得多,并且可能包含错误,但我从 Vec3 使用的内容与内存无关。

几个小时后,我完全一无所知。还有什么可能导致这种情况?优化器或 WINAPI 是否在欺骗我……?(嗯,是的,该程序使用 WINAPI 创建了一个窗口,并使用了一个几乎为空的 WndProc,它在 WM_PAINT 上调用我的代码。)

感谢您提前提供帮助。

很抱歉弄得不清楚。这是布局:

// 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,一种可能的解释是您在某处有一些代码试图将浮点无穷大转换为 int。发生这种情况时,MSVC 2013 中的一个错误会导致对 x87 FPU 堆栈的不平衡推送。触发该错误 8 次,您的 FPU 堆栈完全已满,任何后续尝试推送值(例如调用 'exp()')将导致“无效操作”并返回不确定的(如 1.#IND) . 请注意,即使您使用 SSE2 浮点指令进行编译,这个 bug 仍然存在,因为调用约定规定浮点返回值在 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)

如果您查看::BlackBody实现,我敢打赌您在某处有除以 0 的错误。

于 2014-01-21T21:04:31.320 回答