std::vector<float> Base_LNA_1_2_Mer_AGP( const ui...
作成日: 2025年8月21日
使用モデル GPT-5 Thinking by Chat01
作成日: 2025年8月21日
使用モデル GPT-5 Thinking by Chat01
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 uint32_t r,
const bool mode, const float epsilon, const uint32_t seed) {
if (N == 1u) {
const uint32_t global_iterations_val = global_iterations;
const float b_val = b;
const float initial_length = b_val - a;
float dmax = initial_length;
const uint32_t r_val = r;
const bool use_mode = mode;
const float epsilon_val = epsilon;
std::vector<float> Extr;
std::vector<Interval> R;
Extr.reserve(global_iterations_val);
R.reserve(global_iterations_val + 1u);
float best_f = ShekelFunc(a, seed);
Extr.emplace_back(best_f);
const float end_val = ShekelFunc(b_val, seed);
R.emplace_back(std::make_pair(a, best_f),
std::make_pair(b_val, end_val), N);
float Mmax = R.front().M;
float m = r_val * Mmax;
std::pair<float, float> x_Rmax = std::make_pair(a, b_val);
std::pair<float, float> y_Rmax = std::make_pair(best_f, end_val);
uint32_t schetchick = 0u;
textwhile (true) { const float x1 = x_Rmax.first; const float x2 = x_Rmax.second; const float y1 = y_Rmax.first; const float y2 = y_Rmax.second; const float new_point = Shag(m, x1, x2, y1, y2, N, r_val); const float new_value = ShekelFunc(new_point, seed); const std::pair<float, float> promejutochnaya_tochka = std::make_pair(new_point, new_value); if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } if (schetchick == global_iterations_val) { Extr.emplace_back(schetchick); const Interval& front = R.front(); Extr.emplace_back(front.end.first - front.start.first); return Extr; } std::pop_heap(R.begin(), R.end(), Compare); const Interval promejutochny_otrezok = std::move(R.back()); Interval curr(promejutochny_otrezok.start, promejutochnaya_tochka, N); Interval curr1(promejutochnaya_tochka, promejutochny_otrezok.end, N); const float currM = (curr1.M > curr.M) ? curr1.M : curr.M; const float len2 = promejutochny_otrezok.end.first - new_point; const float len1 = new_point - promejutochny_otrezok.start.first; R.pop_back(); const size_t r_size = R.size(); if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i].end.first - R[i].start.first;
if (len > dmax) dmax = len;
}
}
if (use_mode) {
const float threshold_03 = 0.3f * initial_length;
if (threshold_03 > dmax && schetchick % 3u == 0u ||
10.0f * dmax < initial_length) {
if (currM > Mmax) {
Mmax = currM;
m = r_val * Mmax;
}
const float progress = fmaf(-(1.0f / threshold_03), dmax, 1.0f);
const float alpha = fmaf(progress, progress, 1.0f);
const float betta = 2.0f - alpha;
const float MULTIPLIER = (1.0f / dmax) * Mmax;
const float global_coeff = fmaf(MULTIPLIER, r_val, -MULTIPLIER);
const float GLOBAL_FACTOR = betta * global_coeff;
curr.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr.M * alpha), N);
curr1.ChangeCharacteristic(
fmaf(GLOBAL_FACTOR, len2, curr1.M * alpha), N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i].end.first - R[i].start.first;
R[i].ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i].M * alpha), N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r_val * Mmax;
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r_val * Mmax;
const size_t r_size = R.size();
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i].ChangeCharacteristic(m, N);
}
std::make_heap(R.begin(), R.end(), Compare);
}
else {
curr.ChangeCharacteristic(m, N);
curr1.ChangeCharacteristic(m, N);
}
}
R.emplace_back(std::move(curr));
std::push_heap(R.begin(), R.end(), Compare);
R.emplace_back(std::move(curr1));
std::push_heap(R.begin(), R.end(), Compare);
const Interval& top = R.front();
const float interval_length = top.end.first - top.start.first;
if (interval_length < epsilon_val) {
Extr.emplace_back(schetchick);
Extr.emplace_back(interval_length);
return Extr;
}
x_Rmax = std::make_pair(top.start.first, top.end.first);
y_Rmax = std::make_pair(top.start.second, top.end.second);
++schetchick;
}
} - это чисто нативная функция и она уже хорошо оптимизирована с точки зрения локальности данных, структур данных, векторизации и алгоритмических оптимизаций и fmaf, единственное в чём я сомневаюсь - это локальность данных - возможно можно перегруппировать некоторые строчки кода для лучше локальности данных, также возможно кеширование в начале функции многих аргументов в локальные переменные не даёт выигрыша в скорости а приводит только к замедлению, если действительно можно улучшить локальность данных и поменять некоторые строчки кода местами - то сделай это, если можно улучшить скорость использовав аргументы напрямую без лишнего кеширования - то также сделай это. ВАЖНО - на практике проверено что оптимизация кода близка к максимальной, поэтому я запрещаю тебе сильно и глобально менять код, возможно только рассмотреть два этих вопроса микрооптимизации и применить соответствующие изменения кода только по ним, по остальным вопросам оптимизации кода ты не можешь принимать никаких решений и менять код - но можешь дать мне советы в последнем абзаце
ниже — та же логика, но с микроправками ровно по двум вашим пунктам: (1) локальность/движение данных и (2) отказ от избыточного «кеширования» аргументов в локальные переменные. Алгоритм, структуры данных, векторизацию и fmaf не трогаю.
cppstd::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 uint32_t r, const bool mode, const float epsilon, const uint32_t seed) { if (N == 1u) { // 1) убрал дублирующие *val-переменные: используем аргументы напрямую const float initial_length = b - a; float dmax = initial_length; std::vector<float> Extr; std::vector<Interval> R; Extr.reserve(global_iterations); R.reserve(global_iterations + 1u); float best_f = ShekelFunc(a, seed); Extr.emplace_back(best_f); const float end_val = ShekelFunc(b, seed); 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; // Сохраняем текущий «лучший» отрезок как пары; это дешево, но избегаем лишних обращений к R.front() до перестроения кучи std::pair<float, float> x_Rmax = std::make_pair(a, b); std::pair<float, float> y_Rmax = std::make_pair(best_f, end_val); uint32_t schetchick = 0u; while (true) { const float x1 = x_Rmax.first; const float x2 = x_Rmax.second; const float y1 = y_Rmax.first; const float y2 = y_Rmax.second; const float new_point = Shag(m, x1, x2, y1, y2, N, r); const float new_value = ShekelFunc(new_point, seed); // 2) не делаем promejutochnaya_tochka const, чтобы разрешить перемещения дальше std::pair<float, float> promejutochnaya_tochka = std::make_pair(new_point, new_value); if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } if (schetchick == global_iterations) { Extr.emplace_back(schetchick); const Interval& front = R.front(); Extr.emplace_back(front.end.first - front.start.first); return Extr; } // 3) избегаем лишнего копирования элемента с вершины кучи: убираем const, чтобы move действительно был move std::pop_heap(R.begin(), R.end(), Compare); Interval promejutochny_otrezok = std::move(R.back()); Interval curr (promejutochny_otrezok.start, promejutochnaya_tochka, N); Interval curr1(promejutochnaya_tochka, promejutochny_otrezok.end, N); const float currM = (curr1.M > curr.M) ? curr1.M : curr.M; const float len2 = promejutochny_otrezok.end.first - new_point; const float len1 = new_point - promejutochny_otrezok.start.first; R.pop_back(); // 4) размер R считаем один раз на итерацию (после pop_back) const size_t r_size = R.size(); if (len2 + len1 == dmax) { dmax = (len2 > len1) ? len2 : len1; #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { const float len = R[i].end.first - R[i].start.first; if (len > dmax) dmax = len; } } if (mode) { const float threshold_03 = 0.3f * initial_length; // 5) лёгкая локальность/алгебра: избегаем двух делений подряд, храним обратные значения в регистрах const bool need_global = (threshold_03 > dmax && (schetchick % 3u == 0u)) || (10.0f * dmax < initial_length); if (need_global) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float inv_threshold_03 = 1.0f / threshold_03; const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float inv_dmax = 1.0f / dmax; const float MULTIPLIER = inv_dmax * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr .ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr .M * alpha), N); curr1.ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1.M * alpha), N); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { const float len_item = R[i].end.first - R[i].start.first; R[i].ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i].M * alpha), N); } std::make_heap(R.begin(), R.end(), Compare); } else { if (currM > Mmax) { Mmax = currM; m = r * Mmax; curr .ChangeCharacteristic(m, N); curr1.ChangeCharacteristic(m, N); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { R[i].ChangeCharacteristic(m, N); } std::make_heap(R.begin(), R.end(), Compare); } else { curr .ChangeCharacteristic(m, N); curr1.ChangeCharacteristic(m, N); } } } else { if (currM > Mmax) { Mmax = currM; m = r * Mmax; curr .ChangeCharacteristic(m, N); curr1.ChangeCharacteristic(m, N); #pragma loop(ivdep) for (size_t i = 0u; i < r_size; ++i) { R[i].ChangeCharacteristic(m, N); } std::make_heap(R.begin(), R.end(), Compare); } else { curr .ChangeCharacteristic(m, N); curr1.ChangeCharacteristic(m, N); } } R.emplace_back(std::move(curr)); std::push_heap(R.begin(), R.end(), Compare); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), Compare); const Interval& top = R.front(); const float interval_length = top.end.first - top.start.first; if (interval_length < epsilon) { Extr.emplace_back(schetchick); Extr.emplace_back(interval_length); return Extr; } // обновляем рабочий отрезок на следующую итерацию x_Rmax = std::make_pair(top.start.first, top.end.first); y_Rmax = std::make_pair(top.start.second, top.end.second); ++schetchick; } } // ... остальная часть функции без изменений ... }
*_val
, use_mode
и т.п.). Современный компилятор и так держит аргументы в регистрах/SSA; лишние локальные копии только повышают регистровое давление и создают лишние записи в стек при проливе.const Interval promejutochny_otrezok = std::move(R.back());
на без const
, чтобы реально задействовать move-ctor (иначе будет копирование).R
перенёс в одно место на итерацию (после pop_back()
), чтобы не читать R.size()
повторно и не держать лишние временные переменные в разных ветках.inv_threshold_03
и inv_dmax
, чтобы исключить повторные деления; это улучшает ILP и экономит порт деления.R
и связанный с ним пересчёт характеристик компактным «блоком», уменьшая «разброс» по данным в кэше.ABI передаёт ваши параметры в регистры; внутри функции оптимизатор (SSA) обращается к ним как к виртуальным регистрам. Создание констант-дублёров:
Советы (без изменений кода): соберите с -O3 -march=native -ffast-math
(если допускается), попробуйте PGO (профильная компиляция) — для кучи/перестроений это даёт реальный прирост. На уровне типов имеет смысл проверить, что у Interval
есть noexcept-move и что поля упорядочены без «дырок» (aligning/packing); также выгодно пометить Compare
как inline
и убедиться, что R
никогда не реаллоцируется (при необходимости — слегка завысить reserve
). Для диагностики локальности используйте perf + pmu
(L1-dcache-load-misses, LLC-load-misses) и -fno-omit-frame-pointer
на профилировку; для проверки эффекта отмены кеширования сравните ассемблер -S -fverbose-asm
— вы увидите меньше проливов и mov’ов.