【问题标题】:Why is an intermediate result cast to long before it is assigned to an int?为什么在将中间结果分配给 int 之前将其转换为 long?
【发布时间】:2021-10-01 22:27:51
【问题描述】:

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

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问题的解法。在这里,由于返回类型是 int,我们最终将转换为 int,但在此之前,我们首先将其转换为 long。当我尝试将 long 更改为 int 时,出现运行时错误。如果有人知道答案,请分享:)

【问题讨论】:

  • “有点大”是什么意思?
  • y的类型是什么?这个演员表可能什么也没做。
  • 竞争性编程是它自己的事情,不应该绝对用作如何做好编程的指南。 “竞争性编程”使用的做法在真正的实用代码中非常糟糕。
  • 大概MOD 可以大于46340,在这种情况下MOD*MOD 可以溢出int。所以计算以long 完成。但最终结果是模 MOD,它可能再次适合 int
  • 在此代码中使用long 仅在sizeof(long) &gt; sizeof(int) 时才有意义,并非每个编译器都能保证。

标签: c++ casting multiplication integer-overflow


【解决方案1】:

有问题的行是

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

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

看看为了使这个逻辑健壮而必须执行的情况(如果longint 具有相同的值范围,则强制转换是徒劳的)我希望std::numeric_limits&lt;T&gt; 中有一个模板,如@ 987654342@ 表示对于每个 T2 类型的 arg,返回该值是否可以转换为 T 而不会溢出。

【讨论】:

    猜你喜欢
    • 2015-03-01
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2015-12-15
    相关资源
    最近更新 更多