为什么在将中间结果分配给 int 之前将中间结果强制转换为 long?

Why is an intermediate result cast to long before it is assigned to an int?

在 Codeforces 和 Codechef 的许多编码流和解决方案中,我看到当数字有点大并且我们需要将其分配给 int 然后而不是将其转换为 int 我们将其转换为 long

int maxAreaOfCake(int h, int w, vector<int>& hCuts, vector<int>& vCuts)
{
    hCuts.push_back(0);
    hCuts.push_back(h);

    vCuts.push_back(0);
    vCuts.push_back(w);

    int MOD = 100000007;

    sort(hCuts.begin(), hCuts.end());
    sort(vCuts.begin(), vCuts.end());

    int horizontal = 0;
    for(int i = 0; i < (int)hCuts.size() - 1; i++) horizontal = max(horizontal, hCuts[i+1] - hCuts[i]);
    

    int vertical = 0;
    for(int i = 0; i < (int)vCuts.size() - 1; i++) vertical = max(vertical, vCuts[i+1] - vCuts[i]);
    
    return (int) ((long)horizontal%MOD * (long)vertical%MOD)%MOD;
}

是leetcode中MaxAreaOfCake题的解法。由于 return 类型最终是 int,所以我们要转换为 int,但在此之前我们首先将其转换为 long。当我尝试将 long 更改为 int 时,出现运行时错误。如果有人知道答案,请分享:)

有问题的行是

return (int) ((long)horizontal%MOD * (long)vertical%MOD)%MOD;

long 的转换确保表达式 (long)horizontal%MOD * (long)vertical%MOD 是两个 long 值的乘积。 C 和 C++ 将算术运算的结果计算为其操作数的“最大”类型;如果将两个 int 相乘,结果也是 int。如果数学结果对于 int 来说太大,则会导致有符号溢出,这是未定义的行为。如果 horizontal%MOD * vertical%MOD 大于最大的 int,就会发生这种情况,例如,因为操作数大于最大 int 值的平方根。为了防止代码将操作数转换为long,希望long的取值范围更大(这可能是也可能不是)。如果为真,则结果通常总是适合 long(因为通常最大值 int 小于最大 long 的平方根)。然后乘法的结果用于计算其模数 MOD,它永远不会大于 MOD-1,因此小于最大值 int。因此,将最终结果转换回 int 是安全的,这就是第一个 (int) 做。但是大的中间结果,在最后的取模之前,必须在一个更大的取值范围类型中计算。

看看为了使这个逻辑健壮而必须执行的情况(如果 longint 具有相同的值范围,则转换是徒劳的)我希望有一个模板在 std::numeric_limits<T> 中,例如 bool would_overflow(T2 arg) 对于每个 T2 类型的参数 returns 该值是否可以转换为 T 而不会溢出。