为什么在将中间结果分配给 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)
做。但是大的中间结果,在最后的取模之前,必须在一个更大的取值范围类型中计算。
看看为了使这个逻辑健壮而必须执行的情况(如果 long
和 int
具有相同的值范围,则转换是徒劳的)我希望有一个模板在 std::numeric_limits<T>
中,例如 bool would_overflow(T2 arg)
对于每个 T2 类型的参数 returns 该值是否可以转换为 T 而不会溢出。
在 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)
做。但是大的中间结果,在最后的取模之前,必须在一个更大的取值范围类型中计算。
看看为了使这个逻辑健壮而必须执行的情况(如果 long
和 int
具有相同的值范围,则转换是徒劳的)我希望有一个模板在 std::numeric_limits<T>
中,例如 bool would_overflow(T2 arg)
对于每个 T2 类型的参数 returns 该值是否可以转换为 T 而不会溢出。