代码之家  ›  专栏  ›  技术社区  ›  Steve314

如何在没有未定义行为的情况下进行双块加法?

  •  9
  • Steve314  · 技术社区  · 14 年前

    编辑 公共健康警告-这个问题包括一个关于未定义行为的错误假设。见公认答案。

    阅读之后 recent blog post 我一直在思考避免C和C++代码中所有标准未定义假设的实用性。这里是一个从C++中删去的片段,做一个无符号的128位加法…

    void c_UInt64_Pair::operator+= (const c_UInt64_Pair &p)
    {
      m_Low  += p.m_Low;
      m_High += p.m_High;
    
      if (m_Low < p.m_Low)  m_High++;
    }
    

    这显然依赖于对溢出行为的假设。显然,大多数机器都可以支持正确类型的二进制整数(尽管可能是从32位块或任何东西构建的),但乐观主义者显然越来越有可能利用这里未定义的标准行为。这是 m_Low < p.m_Low 条件可以通过是如果 m_Low += p.m_Low 溢出,这是未定义的行为,因此乐观主义者可以合法地决定 总是

    因此,问题是。。。

    假设您有一个合适的64位二进制机器整数,但是您有一个恶意编译器,它总是以最坏的(或不可能的)方式解释您的未定义行为。另外,假设你 不要

    小说明-这不仅仅是关于检测溢出,还包括确保m泷u Low和m泷u High最终得到正确的模2^64结果,这也是标准未定义的。

    2 回复  |  直到 14 年前
        1
  •  17
  •   David Thornley    14 年前

    从C++ 1998标准中,3.91(4):“无符号整数,声明未签名,应该服从算术模2 ^ n的法则,其中n是该特定大小的整数的值表示的位数。” int .

    因此,假设那些是无符号整数,就像类型中的“UIT64”所示,这是C++中定义的行为,应该按照预期的方式工作。

        2
  •  0
  •   swestrup    14 年前

    如果你想要一个实际有效的方法,你必须用C或C++以外的东西来编码。为了 合理地 高效,您必须确保溢出永远不会发生,并在发生溢出时进行检测和补偿。

    基本上,对于每个64位组件,您需要使用低63位和最高位分别计算加法。从这些单独的计算中,您可以计算出64位的总数,以及是否有进位。

    然后,当你做上64位加法时,如果有进位的话,你就把进位加进去。如果由此产生进位,那么您已经溢出了128位变量,您需要触发一个异常,或者以其他方式处理该情况。