OP 遇到了灵异事件

既然所有变量都已初始化,并且排除了浮点除零的问题,那我们需要进一步细化调试过程和代码结构,来检查是否存在其他潜在的未定义行为,尤其是在不同优化等级下的表现不同。

分析与调试思路

  1. 检查循环和赋值:确保所有循环和条件赋值都正确执行,尤其在高优化级别下。
  2. 调试日志:在关键位置添加调试日志,输出变量值和执行路径,帮助确定在哪个环节出现异常。
  3. 优化等级影响:不同优化等级-O0, -O1, -O2, -O3 会导致编译器进行不同的代码优化路径,需要确认在每种优化等级下的行为。

调试日志

通过在代码关键位置增加调试信息,帮助分析变量状态和执行流程。示例如下:

#include <iostream>
#include <cfloat>
#include <map>
#include <climits> // 引入 INT_MIN

using namespace std;

typedef long long ll;

const string no_solution = "NO SOLUTION";

void solve() {
    int expected;
    cin >> expected;
    int sales_at_expected = 0; // 初始化为 0

    double min_M = DBL_MAX;
    double max_m = DBL_MIN;

    map<int, int> input;

    // w = sales * subsidy + c
    // c = sales * (price - cost)
    int cost, sales_at_cost;
    cin >> cost >> sales_at_cost;
    input[cost] = sales_at_cost;
    
    int p, s;
    int max_p = INT_MIN; // 初始化为一个最小值
    int max_p_s;
    while (cin >> p >> s && p != -1) {
        max_p = max(p, max_p);

        if (p == expected) {
            sales_at_expected = s;
        }

        input[p] = s;
    }

    // 打印调试信息
    cerr << "Initial input map: ";
    for (const auto &pair : input) {
        cerr << " (" << pair.first << "," << pair.second << ")";
    }
    cerr << endl;

    // calculate unknown
    max_p_s = input[max_p];
    int decrement;
    cin >> decrement;
    while ((max_p_s -= decrement) >= 0) {
        input[++max_p] = max_p_s;
    }

    sales_at_expected = input[expected];

    // 打印调试信息
    cerr << "Updated input map: ";
    for (const auto &pair : input) {
        cerr << " (" << pair.first << "," << pair.second << ")";
    }
    cerr << endl;

    // calculate intersections
    ll c_expected = sales_at_expected * (expected - cost);
    for (const auto &pair : input) {
        auto &pi = pair.first;
        auto &si = pair.second;
        ll ci = (pi - cost) * si;
        if (si - sales_at_expected < 1e-5) continue; // 已修正的除零检查
        double subsidy = double(c_expected - ci) / double(si - sales_at_expected);

        cerr << "pi = " << pi << ", si = " << si << ", subsidy = " << subsidy << endl;

        if (pi < expected && subsidy < min_M) min_M = subsidy;
        else if (pi > expected && subsidy > max_m) max_m = subsidy;
    }

    // find result
    ll ans = ll(max_m + 1.0);

    cerr << "max_m = " << max_m << ", min_M = " << min_M << ", ans = " << ans << endl;

    if (ans > min_M) cout << no_solution << endl;
    else cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(false);

    solve();

    return 0;
}

通过在关键位置打印调试信息,可以帮助追踪变量值和代码执行路径,尤其在不同的优化等级下。具体调试思路如下:

  1. 编译和运行:分别在不同优化等级 -O0, -O1, -O2, -O3 下编译和运行代码。
  2. 检查调试输出:对比不同优化等级下输出的调试日志,分析是否存在变量值异常或执行路径不一致的地方。

请尝试使用上述调试日志分析不同运行结果,以确定代码在不同优化等级下为何会表现不同。这将有助于进一步确定未定义行为的根源。

应该是这个问题,我再看看

不对啊,你的 max_p 在第一次塞入 max 前没有赋值?这是一个 UB(应该),会导致你最后 input[max_p] 的时候取到不在 map 内的 key

所以 aibot,你第一句话就发现了吗?好厉害,可惜没有小费能给你 :wink:

1 Like

c–的 undefined behavior 真 tm sb

1 Like

所以编译器优化之后,对于未定义变量会随便取一个值,然后同一次运行只内每次取的也能不一样么

根据楼上的 link,确实是这样的
不对不对,是内存,刚没注意到 :sweat_smile:

准确地说,如果内存是未初始化的,编译器可以在每次引用这部分内存时假设它是任意值(一般是对于求值来说更“方便”的值,以便进行优化),并且不需要保持前后任意次对同一块未初始化内存区域的这种假设的一致性。

但是这可能还并不能完全解释清楚程序的结果在 1 和 4 之间反复横跳的全部原因,个人建议使用 -fsanitize 编译选项,指定适当的 Sanitizer,以便更为严格地捕获异常行为。

2 Likes