Я работал над реализацией излучения черного тела в соответствии с законом Планка со следующим:
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;
}
У меня есть массив с плавающей запятой[max-min+1], где static const int max=780, static const int min = 380. Я просто перебираю массив и добавляю то, что дает BlackBody для длины волны (длина волны = массив- индекс + мин). 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);
}
}
Проблема в том, что строка spec.BlackBody() устанавливает 0-й элемент массива в NaN, и только 0-й. Также это происходит не для самой первой итерации, а для всех последующих, где xc>=10.
Текст из отладчика VS: spec = {intensity=0x009bec50 {-1.#IND0000, 520718784., 537559104., 554832896., 572547904., 590712128., 609333504., ...} }
Я отследил ошибку, и exppart в функции ::BlackBody() становится 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);
double BlackBody(double T, double wavelength)
, что, по-видимому, не то, что вы вызываете в другом блоке кода. Там вы звонитеIntensitySpectrum::BlackBody(float)
илиIntensitySpectrum::BlackBody(double)
. Второго аргумента нет, и вы не используете возвращаемое значение из этого вызова функции. - person David Hammen   schedule 22.01.2014