#pragma once #include "pch.h" #include <Objbase....

创建于:2025年8月30日

使用 GPT-5 Thinking 回答 Chat01

问题

#pragma once

#include "pch.h"

#include <Objbase.h>

extern "C" __declspec(dllexport) float __cdecl xor_rand_grsh(uint32_t& __restrict state) noexcept
{
uint32_t s = state;
s ^= s << 13u;
s ^= s >> 17u;
s ^= s << 5u;
state = s;
return fmaf(s, 0x1.0p-31f, -1.0f);
}

extern "C" __declspec(dllexport) float __cdecl xor_rand(uint32_t& __restrict state)
{
uint32_t s = state;
s ^= s << 13u;
s ^= s >> 17u;
s ^= s << 5u;
state = s;
return s * 0x1.0p-32f;
}

static float HillFunc(const float x, uint32_t seed) noexcept
{
int32_t i = 0;
__declspec(align(64u)) float angles[14u];
const float start_angle = 6.28318530717958647692f * x;

#pragma loop(ivdep)
while (i < 14) {
angles[i] = start_angle * (i + 1);
++i;
}

text
__declspec(align(64u)) float sin_vals[14u]; __declspec(align(64u)) float cos_vals[14u]; fabe13_sincos_scalar_simple(angles, sin_vals, cos_vals, 14u); float res = fmaf(xor_rand(seed), 2.0f, -1.1f); --i; while (i >= 0) { res += fmaf(fmaf(xor_rand(seed), 2.0f, -1.1f), sin_vals[i], fmaf(xor_rand(seed), 2.0f, -1.1f) * cos_vals[i]); --i; } return res;

}

extern "C" __declspec(dllexport) float __cdecl ShekelFunc(float x, uint32_t seed)
{
uint32_t i = 0u;
float res = 0.0f;

text
while (i < 10u) { const float r = xor_rand(seed); const float x_part = fmaf(-r, 10.0f, x); res -= 1.0f / fmaf(fmaf(xor_rand(seed), 20.0f, 5.0f), x_part * x_part, fmaf(xor_rand(seed), 0.2f, 1.0f)); ++i; } return res;

}

static float GrishaginFunc(const float x1, const float x2, uint32_t seed) noexcept
{
int32_t i = 0;
__declspec(align(64u)) float angles_i[8u];
__declspec(align(64u)) float angles_j[8u];

#pragma loop(ivdep)
while (i < 8) {
const float pi_mult = 3.14159265358979323846f * (i + 1);
angles_i[i] = pi_mult * x1;
angles_j[i] = pi_mult * x2;
++i;
}

text
__declspec(align(64u)) float sin_i[8u], cos_i[8u]; __declspec(align(64u)) float sin_j[8u], cos_j[8u]; fabe13_sincos_scalar_simple(angles_i, sin_i, cos_i, 8u); fabe13_sincos_scalar_simple(angles_j, sin_j, cos_j, 8u); --i; float part1 = 0.0f; float part2 = 0.0f; while (i >= 0) { uint32_t j = 0u; while (j < 8u) { const float sin_term = sin_i[i] * sin_i[i]; const float cos_term = cos_j[j] * cos_j[j]; part1 = fmaf(xor_rand_grsh(seed), sin_term, fmaf(xor_rand_grsh(seed), cos_term, part1)); part2 = fmaf(-xor_rand_grsh(seed), cos_term, fmaf(xor_rand_grsh(seed), sin_term, part2)); ++j; } --i; } return -sqrtf(fmaf(part1, part1, part2 * part2));

}

extern "C" __declspec(dllexport) float __cdecl RastriginFunc(const float x1, const float x2) noexcept
{
const float term1 = fmaf(x1, x1, x2 * x2);
return (term1 - fmaf(
fabe13_cos(6.28318530717958647692f * x1) +
fabe13_cos(6.28318530717958647692f * x2),
10.0f,
-14.6f)) *
fmaf(-term1, 0.25f, 18.42f);
}

extern "C" __declspec(dllexport) float __cdecl Shag(const float _m, const float x1, const float x2, const float y1,
const float y2, const uint32_t _N, const float _r) noexcept
{
const float diff = y2 - y1;
return _N == 1u
? fmaf(-(1.0f / _m), diff, x1 + x2) * 0.5f
: diff > 0.0f
? fmaf(-(1.0f / (_m * _m)), (diff) * (diff)_r, x1 + x2) * 0.5f
: fmaf(1.0f / (_m * _m), (diff) * (diff)
_r, x1 + x2) * 0.5f;
}

__declspec(align(32u)) struct Interval final
{
public:
std::pair<float, float> start;
std::pair<float, float> end;
float M;
float R;

text
__declspec(noalias) __forceinline Interval(const std::pair<float, float>& __restrict _start, const std::pair<float, float>& __restrict _end, const uint32_t _N) noexcept : start(_start) , end(_end) , M(_N == 1u ? fabsf(_end.second - _start.second) * (1.0f / (_end.first - _start.first)) : _N == 2u ? fabsf(_end.second - _start.second) * (1.0f / sqrtf(_end.first - _start.first)) : fabsf(_end.second - _start.second) * (1.0f / powf(_end.first - _start.first, 1.0f / float(_N)))) { } __declspec(noalias) __forceinline void ChangeCharacteristic(const float _m, const uint32_t _N) noexcept { const float delta_x = end.first - start.first; const float delta_y = end.second - start.second; switch (_N) { case 1u: R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, delta_x, (delta_y * delta_y) * (1.0f / (_m * delta_x)))); break; case 2u: { const float sqrt_dx = sqrtf(delta_x); R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, sqrt_dx, (delta_y * delta_y) * (1.0f / (_m * sqrt_dx)))); } break; default: { const float pow_dx = powf(delta_x, 1.0f / _N); R = fmaf( -(end.second + start.second), 2.0f, fmaf(_m, pow_dx, (delta_y * delta_y) * (1.0f / (_m * pow_dx)))); } } }

};

extern "C" __declspec(dllexport) bool __cdecl Compare(const Interval& __restrict a, const Interval& __restrict b) noexcept
{
return a.R < b.R;
}

const __declspec(noalias) __forceinline PeanoCurve_2D* PeanoCurve_2D::HitTest_2D(float x) const noexcept
{
uint32_t i = 0u;
const uint32_t _razvertka = this->razvertka;
uint32_t num;
const float this_a = this->a;
x -= this_a;
const float b_minus_a = this->b - this_a;
const float inv_b_minus_a = 1.0f / b_minus_a;
const PeanoCurve_2D* Curr = this;

text
while (i != _razvertka) { const uint32_t shift = 1u << ++i + i; num = shift * x * inv_b_minus_a; x = fmaf(-ldexp(1.0f, -(i << 1)) * num, b_minus_a, x); const List currType = Curr->Type; switch (num) { case 0u: Curr = (currType == Top || currType == Right) ? Curr->DownLeft.get() : Curr->TopRight.get(); break; case 1u: Curr = (currType == Top || currType == Left) ? Curr->TopLeft.get() : Curr->DownRight.get(); break; case 2u: Curr = (currType == Top || currType == Right) ? Curr->TopRight.get() : Curr->DownLeft.get(); break; case 3u: Curr = (currType == Top || currType == Left) ? Curr->DownRight.get() : Curr->TopLeft.get(); } } return Curr;

}

const __declspec(noalias) __forceinline float PeanoCurve_2D::FindX_2D(float target_x1, float target_x2) const noexcept
{
uint32_t _razvertka = this->razvertka;
uint32_t _razvertka1 = _razvertka;
float x1, x2, x = this->a;
const float b_minus_a = this->b - x;
const PeanoCurve_2D* Curr = this;

text
while (_razvertka != 0u) { const uint32_t exponent = _razvertka1 - _razvertka-- << 1u; x1 = Curr->x1; x2 = Curr->x2; const List currType = Curr->Type; if (target_x1 > x1 && target_x2 > x2) { Curr = Curr->TopRight.get(); if (currType == Top || currType == Right) { x = fmaf(ldexp(1.0f, -exponent) * 0.5f, b_minus_a, x); } } else if (target_x1 < x1 && target_x2 > x2) { Curr = Curr->TopLeft.get(); if (currType == Top || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.25f, b_minus_a, x); } else { x = fmaf(ldexp(1.0f, -exponent) * 0.75f, b_minus_a, x); } } else if (target_x1 < x1 && target_x2 < x2) { Curr = Curr->DownLeft.get(); if (currType == Down || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.5f, b_minus_a, x); } } else { Curr = Curr->DownRight.get(); if (currType == Top || currType == Left) { x = fmaf(ldexp(1.0f, -exponent) * 0.75f, b_minus_a, x); } else { x = fmaf(ldexp(1.0f, -exponent) * 0.25f, b_minus_a, x); } } } return x;

}

extern const boost::mpi::communicator world;

extern std::unique_ptr<PeanoCurve_2D> Curve;
extern std::unique_ptr<PeanoCurve_2D> Curve_Inverted;

struct CrossMsg final {
float s_x1, s_x2;
float e_x1, e_x2;
float Rtop;
template <typename Archive>
__declspec(noalias) __forceinline void serialize(Archive& __restrict ar, const unsigned int) noexcept { ar& s_x1& s_x2& e_x1& e_x2& Rtop; }
};

std::vector<float> Base_LNA_1_2_Mer_AGP(const uint32_t N,
const uint32_t global_iterations, const float a, const float b, const float c, const float d, const float r,
const bool mode, const float epsilon, uint32_t seed)
{

text
if (N == 1u) { const float initial_length = b - a; float dmax = initial_length; std::vector<float> Extr; Extr.reserve((global_iterations << 1u) + 2u); std::vector<Interval> R; R.reserve(global_iterations + 1u); float best_f = ShekelFunc(a, seed); const float end_val = ShekelFunc(b, seed); uint32_t schetchick = 0u; std::pair<float, float> x_Rmax = std::make_pair(a, b); std::pair<float, float> y_Rmax = std::make_pair(best_f, end_val); R.emplace_back(std::make_pair(a, best_f), std::make_pair(b, end_val), N); float Mmax = R.front().M; float m = r * Mmax; std::vector<float> myVector = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f }; // 2. Делаем что-то с вектором (например, увеличиваем каждый элемент на 10%) for (float& num : myVector) { // Используем ссылку, чтобы изменять оригинальные значения num *= 1.1f; } // 3. Добавляем новый элемент в конец вектора myVector.push_back(6.6f); // 4. Возвращаем модифицированный вектор return myVector; }

}

// C-обёртка: без std::vector в сигнатуре!
extern "C" __declspec(dllexport) int __cdecl Base_LNA_1_2_Mer_AGP_C(
uint32_t N, uint32_t global_iterations, float a, float b, float c, float d, float r,
bool mode, float epsilon, uint32_t seed,
float** out_data, uint32_t* out_len)
{
try {
auto v = Base_LNA_1_2_Mer_AGP(N, global_iterations, a, b, c, d, r, mode, epsilon, seed);
*out_len = (uint32_t)v.size();
out_data = (float)CoTaskMemAlloc(sizeof(float) * (*out_len));
if (!*out_data) return 2; // OOM
memcpy(*out_data, v.data(), sizeof(float) * (*out_len));
return 0; // ok
}
catch (const std::bad_alloc& e) {
if (out_data) *out_data = nullptr;
if (out_len) *out_len = 0;
return 3;
}
catch (const std::exception& e) {
if (out_data) *out_data = nullptr;
if (out_len) *out_len = 0;
return 1;
}
}

extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p) {
CoTaskMemFree(p);
} - это моя DLL библиотека, если я упрощаю основную экспортируюмую функцию возвращающую вектор до std::vector<float> myVector = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f };

text
// 2. Делаем что-то с вектором (например, увеличиваем каждый элемент на 10%) for (float& num : myVector) { // Используем ссылку, чтобы изменять оригинальные значения num *= 1.1f; } // 3. Добавляем новый элемент в конец вектора myVector.push_back(6.6f); // 4. Возвращаем модифицированный вектор return myVector; - то всё работает нормально, но в таком виде в каком она сейчас она вызывает исключения в управляемом коде в котором я её вызываю в myforms приложении, я пометил некоторые остальные функции как экспортируемые так как казалось это уберёт ошибку но не помогло - остальные функции в dll можно пометить статическими и будет тот же эффект, dll и основной проект имеют схожие настройки кроме clr флагов, но все настройки касаемо вычислений с плавающей запятой идентичные, проблема точно не в денормалах, вот код в управляемой форме: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { chart2->Series[0]->Points->Clear(); chart2->Series[1]->Points->Clear(); chart2->Series[2]->Points->Clear(); chart2->Series[3]->Points->Clear(); static LARGE_INTEGER start, end; QueryPerformanceCounter(&start); uint32_t seed = GetTickCount(); typedef int(__cdecl* agp_c)( uint32_t, uint32_t, float, float, float, float, float, bool, float, uint32_t, float**, uint32_t*); typedef void(__cdecl* agp_free)(float*); HINSTANCE h = LoadLibrary(L"TEST_FUNC.dll"); if (!h) { DWORD errorCode = GetLastError(); System::String^ errorMessage = "Ошибка загрузки DLL! Код: " + errorCode.ToString(); System::Windows::Forms::MessageBox::Show(errorMessage); return; } auto f = (agp_c)GetProcAddress(h, "Base_LNA_1_2_Mer_AGP_C"); auto ffree = (agp_free)GetProcAddress(h, "Base_LNA_1_2_Mer_AGP_Free"); if (!f || !ffree) { /* обработать ошибку */ } float* buf = nullptr; uint32_t len = 0; int rc = f(1, 10000, 0.0f, 1.0f, -2.2f, 1.8f, 2.5f, false, 0.0001f, seed, &buf, &len); if (rc == 0) { std::vector<float> Extr_2D(buf, buf + len); ffree(buf); textBox2->Text = Convert::ToString(Extr_2D.back()); // ... используете Extr_2D } само исключение выбрасывается не в управляемом коде а в самой dll в вызове функции шекеля здесь const float r = xor_rand(seed); const float x_part = fmaf(-r, 10.0f, x); - иногда исключение выбрасывается в первой, иногда во второй строчке, при том, что изолированно я проверил что fmaf вычисления у меня работают, здесь также библиотека <cmath> - подключена, функция для рандома также правильна, подскажи в каком направлении копать, какая самая вероятная причина падения, может быть функция шекеля должна принимать ссылку? так как в рандоме используется ссылка, касаемо самой логики функции они правильны - потому что я проверял их изолированно не из dll а в консольном приложении проверял эти функции

思考

Evaluating C++ reference binding

In C++, you can indeed bind a non-const lvalue reference to a non-const lvalue object, but this refers to a local copy, not the original variable. So, it's fine for local variables. However, the issue might arise in functions involving fmaf, possibly with re-entrancy or differences in floating-point behavior when using /fp:fast.

Analyzing floating-point behavior

In managed apps, floating-point exception flags might trap invalid operations, but Windows often masks these exceptions. Issues arise with SSE and operations like denormals or NaNs, although the user doesn't seem concerned with denormals and uses fmaf instead. In MSVC, fmaf is mapped to an FMA instruction (if available under /arch:AVX2). The memory alignment and the fabe13_sincos_scalar_simple function seem important, but I need to check its definition.

Assessing potential stack issues

The issue might be an external called function causing memory corruption, possibly due to a mismatched calling convention, leading to stack corruption. An exception occurs when calling xor_rand, and earlier memory corruption could be causing this. Functions like fabe13_sincos_scalar_simple and fabe13_cos seem to be custom with AVX vectorization, but if the project lacks /arch:AVX2, this could be problematic.

Looking into calling convention mismatch

The functions are in the same DLL, so that's fine. However, a mismatch in the calling convention (e.g., __cdecl vs. __vectorcall) could cause stack corruption. If the prototype doesn’t match the actual function signature, it could lead to unpredictable behavior or crashes, though thread safety doesn’t seem relevant here. I should check for any declaration signature mismatches.

Investigating potential crashes and exceptions

There seem to be several possibilities leading to the crash. If function prototypes don't match, it could corrupt the stack, especially when referencing a variable like state by reference. Additionally, using fmaf or operations like division by zero could lead to floating-point errors if not handled properly. It looks like the exception might arise due to accessing an invalid address within xor_rand.

Suspected issues in ShekelFunc

It seems the primary issue might stem from how xor_rand is handling the state parameter. The function references this parameter by non-const lvalue, which could cause undefined behavior if seed is in a register instead of addressing memory. The exception likely results from an access violation or arithmetic exception triggered by hardware, not a conventional C++ exception.

Analyzing exception causes

The crash seems to be related to a memory access violation, likely due to stack corruption or pointer misuse. There's a mismatch in how xor_rand may be referenced, possibly from a conflict in external declarations or calling conventions. This could explain the inconsistent crashes, especially with the seed pointer being incorrectly treated.

Investigating crash causes

It seems the issue could be stack corruption or a mismatch in how xor_rand is declared and defined across different parts of the code. An alignment or calling convention problem might be at play. The code’s interactions between managed and unmanaged environments also raise a concern about potential memory issues, but it looks like alignment isn't the direct cause.

Investigating function crashes

It looks like the crash could be linked to a mismatch in how xor_rand is declared and how it's used in different modules. There's a chance that calling conventions or references might be causing issues. I'll focus on checking the signatures and possibly making xor_rand static to avoid ambiguity. Mismatched prototypes could also be a culprit.

Debugging the crash

Let's consider likely causes for the crash:

  • Mismatched xor_rand prototype because of extern "C" and reference passing.
  • Possible stack corruption due to fabe13_* declarations, even though they’re not executed.
  • Serialize and check for any ABI mismatches, especially with xor_rand involving references.

I suggest adjusting the function signatures for clarity, using static for internal functions, and mitigating stack corruption risks with further safeguards.

Thought for 3m 25s

回答

Кратко: по симптомам это почти наверняка не “математика”, а ABI/прототип (несовпадение сигнатур / соглашения о вызове / ref vs value) → порча стека/регистров, из-за чего падение иногда в const float r = xor_rand(seed);, иногда в fmaf(...). Когда вы упрощаете функцию и не вызываете ShekelFunc()/xor_rand(), всё ок — как только идёт вызов RNG через ссылку, срабатывает.

Вот куда копать и что изменить (в порядке вероятности/пользы):

1) Уберите extern "C" + & у внутренних функций (или сделайте API pointer-based)

Экспортировать функции с C-линковкой и C++-ссылками — плохая идея. В разных TU легко получить рассинхрон прототипов (особенно при PCH). Достаточно в одном месте объявить xor_rand(uint32_t) (по значению), а где-то определить xor_rand(uint32_t&) — компилятор примет, линковщик тоже, а в рантайме вызов передаст значение вместо адреса → state в xor_rand станет “левым” указателем → падение ровно на строке uint32_t s = state;.

Надёжные варианты:

Вариант А (рекомендую): сделать RNG внутренним и pointer-based

cpp
// .cpp (без dllexport/extern "C") static inline float xor_rand_u32(uint32_t* state) noexcept { uint32_t s = *state; s ^= s << 13u; s ^= s >> 17u; s ^= s << 5u; *state = s; return s * 0x1.0p-32f; } static inline float xor_rand_grsh_u32(uint32_t* state) noexcept { uint32_t s = *state; s ^= s << 13u; s ^= s >> 17u; s ^= s << 5u; *state = s; return fmaf((float)s, 0x1.0p-31f, -1.0f); }

и везде вызывать как:

cpp
const float r = xor_rand_u32(&seed);

Вариант B: если принципиально оставить ссылку — не экспортируйте эти функции, держите их static inline в том же TU, где вызываете; и убедитесь, что есть один общий заголовок с единственной корректной декларацией, который подключается повсюду. После правки — удалите .pch и пересоберите “с нуля”.

2) Проверьте именно это рассинхронирование

  • Поиск по проекту: нет ли где-то объявления float xor_rand(uint32_t state) (без &) или без extern "C", или с другим __stdcall/__vectorcall.
  • На x86 это особенно убийственно: неверная сигнатура = “поехавший” стек → падение “вроде бы” на fmaf/xor_rand.
  • На всякий случай: сделайте явное объявление до использования и статическую проверку:
    cpp
    extern "C" float __cdecl xor_rand(uint32_t& state) noexcept; static_assert(std::is_same_v<decltype(&xor_rand), float(__cdecl*)(uint32_t&)>, "xor_rand prototype mismatch");

3) Сделайте ShekelFunc “честной” к тому, как вы крутите сид

Сейчас ShekelFunc(float x, uint32_t seed) принимает сид по значению (это ок), но тогда RNG меняет только локальную копию. Функционально это нормально, но чтобы исключить любые сюрпризы с адресацией, можно тоже перейти на pointer/reference:

cpp
// либо static float ShekelFunc(float x, uint32_t& seed) noexcept // либо static float ShekelFunc(float x, uint32_t* seed) noexcept

и вызывать консистентно с п.1.

4) Защититесь от FPU/SSE ловушек (если вдруг включены)

В смешанной среде иногда кто-то снимает маски SSE/x87. Это не ваша корневая причина (по формуле деления на 0 быть не должно), но на всякий случай заглушите ловушки в начале экспортируемой C-обёртки:

cpp
#include <float.h> #include <immintrin.h> extern "C" __declspec(dllexport) int __cdecl Base_LNA_1_2_Mer_AGP_C(...){ // Маскируем x87 _controlfp_s(nullptr, _MCW_EM, _MCW_EM); // Маскируем SSE исключения + включаем FTZ/DAZ (по желанию) unsigned mx = _mm_getcsr(); _mm_setcsr(mx | 0x1F80 /*маски*/ | 0x8040 /*FTZ|DAZ*/); __try { auto v = Base_LNA_1_2_Mer_AGP(...); ... return 0; } __except(EXCEPTION_EXECUTE_HANDLER) { if (out_data) *out_data = nullptr; if (out_len) *out_len = 0; return 4; // аппаратное исключение } }

5) Ещё мелкие, но полезные правки/проверки

  • Сигнатуры fabe13_*: если где-то объявлены с другим соглашением (__vectorcall vs __cdecl) или другим набором параметров — это мгновенная порча стека. Пусть у них будет один общий заголовок с точной сигнатурой. (Для вашего кейса N==1 они не вызываются, но держите в уме.)
  • Приоритет в HitTest_2D: выражение 1u << ++i + i читается как 1u << (++i + i). Если там ожидалась другая логика — расставьте скобки явно. Это не влияет на N==1 ветку, но потенциально минное поле.
  • x86 vs x64 / MDd vs MD: убедитесь, что разрядность DLL и процесса совпадает (иначе LoadLibrary бы упал) и что обе сборки на /MD (CRT в DLL вы обходите через CoTaskMemAlloc, это правильно).
  • Полные пересборки: после правок заголовков/PCH обязательно “Clean + Rebuild” обоих проектов.

Минимальный патч (без смены логики), который чаще всего чинит проблему

  1. Сделать RNG невидимым снаружи и pointer-based (вариант А).
  2. В ShekelFunc заменить вызовы на xor_rand_u32(&seed).
  3. Удалить все dllexport/extern "C" у внутренних функций; экспорт оставить только у C-обёрток.
  4. Полная пересборка без PCH-артефактов.

Если после этого всё ещё падает — почти наверняка где-то осталась неправильная декларация одной из функций. В таком случае откройте листинг вызова xor_rand (ассемблер): вы должны видеть передачу адреса переменной seed (на x64 — через регистр с последующим обращением по памяти), а не самого значения. Если передаётся значение — найден источник.

分享这个问答