【问题标题】:Why does INTMAX_MAX give wrong result here?为什么 INTMAX_MAX 在这里给出错误的结果?
【发布时间】:2016-01-07 06:48:43
【问题描述】:

我遇到了一个问题,要求我在任何给定顶点对之间找到最大的最便宜路径。我为解决方案实现了 Floyd Warshall 算法。但是我的程序中有一个奇怪的错误。我使用 intmax_t 来避免溢出,但是如果我使用 INTMAX_MAX 而不是 INT_MAX 来表示两个顶点没有直接连接,我会得到错误的答案。为什么会这样?

#include <bits/stdc++.h>
using namespace std;
struct _ { ios_base::Init _i; _() { cin.sync_with_stdio(0); cin.tie(0); } } _;

#define endl '\n'
#define int intmax_t
#define in(x) for (auto& i: x)
#define test int _t; cin >> _t; for (int i=1; i<=_t; i++) {

signed main()
{
    int v, e, ans=INT_MIN;
    cin >> v >> e;
    int g[v+1][v+1];
    for (int i=1; i<=v; i++)
        for (int j=1; j<=v; j++)
            g[i][j]=INT_MAX;
    for (int i=0; i<e; i++)
    {
        int x, y, p;
        cin >> x >> y >> p;
        g[x][y]=g[y][x]=p;
    }
    for (int i=1; i<=v; i++)
        for (int j=1; j<=v; j++)
            for (int k=1; k<=v; k++)
                g[j][k]=min(g[j][k], g[j][i]+g[i][k]);
    for (int i=1; i<=v; i++)
        for (int j=1; j<=v; j++)
            if (g[i][j]!=INT_MAX && i!=j)
                ans=max(ans, g[i][j]);
    cout << ans;
}

如果我将 INT_MIN 替换为 INTMAX_MIN 并将 INT_MAX 替换为 INTMAX_MAX,则会得到不正确的结果。

示例案例:

使用 INT_MAX:http://ideone.com/ffmv7P

使用 INTMAX_MAX:http://ideone.com/vjMCuE

附录:该程序是专门为解决竞争性编程问题而编写的。请将您的“正确编码实践”建议留给自己。如果您愿意回答,您会发现预处理器指令在这种情况下对可读性造成的影响很小或没有问题。他们在那里是有原因的,我并不愚蠢。如果您没有竞争性编程经验,请不要将责任归咎于我。谢谢。

【问题讨论】:

  • 你认为 INTMAX_MAX + INTMAX_MAX 是什么?另外,说真的,清理那些恶心的宏。
  • 现在我也看到了signed main()...
  • 哦,谢谢。我应该仔细选择无限值。关于“恶心的宏”,只有一个宏,为什么恶心?这是一个有竞争力的编程问题,in 宏有时会派上用场以节省时间。我的问题甚至与此无关,它不会影响我所问的内容。签名是为了补偿 intmax_t 指令。
  • #define int intmax_t -- 我强烈建议不要这样做。使用typedef,而不是宏,并给它一个除int以外的名称。
  • 首先是using namespace std;,然后是#define endl '\n'...真的吗?为什么?

标签: c++ numeric-limits


【解决方案1】:

您正在添加数字并有可能溢出。使用INT_MAX 时,您正在使用可能低于intmax_t 范围的数字初始化单元格(这是单元格的真实类型)。那就是INT_MAX+INT_MAX 很可能适合intmax_t 而不会溢出,而INTMAX_MAX+INTMAX_MAX 绝对不会。

您遇到整数溢出,理论上它具有未定义的行为。很可能在现实中它不能很好地与比较一起使用,因为整数溢出会包装成负数,使INTMAX_MAX+INTMAX_MAXINTMAX_MAX 小得多(它甚至可以变成负数)。

如果您有一个编译器,其中 int 具有相同的范围 intmax_t(这并非不切实际),那么您的代码在这两种情况下都应该失败。

【讨论】:

  • 我一直在做这个g[v+1]类型分配很长时间了。从来没有遇到过在线评委的任何意外行为。这里的问题只是INTMAX_MAX+INTMAX_MAX根据定义大于intmax_t可以存储的最大值,对吧?
  • @AnukulSangwan g[v+1] 的问题是v 未初始化,v 为负数(或者可能是旧版本的语言)。也许您以前没有使用过未初始化的值?未初始化的变量应该是一个真正的问题,考虑如果v 恰好为负数、太大(对于内存)或不够大(对于xs 和ys)会发生什么。所以这里的(潜在)问题不仅仅是INTMAX_MAX+INTMAX_MAX
  • 好的,知道为什么我从来没有发生过这种情况吗?当 v 的未初始化值为负数时程序崩溃。
  • @AnukulSangwan 对不起,我的错误。当您从 cin 读取它时,v 并未未初始化。我会更新我的答案。
【解决方案2】:

您显然不能将 INTMAX_MAX 存储在 int 类型的变量中。你会得到一个溢出,这会导致未定义的行为。在实践中,您通常会得到 INTMAX_MAX 的最后 32 位,它们与 (int) -1 的位模式相同。

另一方面,将 int 与 INTMAX_MAX 进行比较意味着 int 将转换为 intmax_t,但只要类型不同(实际上它们是不同的),int 就永远不会等于 INTMAX_MAX。

【讨论】:

  • 如果sizeof(int) == sizeof(intmax_t),则可以将INTMAX_MAX 存储在一个int 中,尽管可能没有编译器会这样实现
  • @LưuVĩnhPhúc sizeof(int) == sizeof(intmax_t) 的可能性不大。例如,根据 wikipedia (en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models),在 ILP64 或 SILP64 系统上很有可能存在这样的架构。
猜你喜欢
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2021-10-18
相关资源
最近更新 更多