如何正确检查减法之前不会发生整数下溢和溢出? 我目前正在为C++编写一个安全的整数库。我在实施减法时遇到了一些问题

如何正确检查减法之前不会发生整数下溢和溢出? 我目前正在为C++编写一个安全的整数库。我在实施减法时遇到了一些问题,c++,integer,subtraction,integer-overflow,C++,Integer,Subtraction,Integer Overflow,以下是我的开始: #include <limits> #include <stdexcept> template<typename I> class safe_int { I val; public: typedef I value_type; static constexpr I max = std::numeric_limits<I>::max(); static constexpr I min = std:

以下是我的开始:

#include <limits>
#include <stdexcept>

template<typename I>
class safe_int
{
    I val;

public:
    typedef I value_type;
    static constexpr I max = std::numeric_limits<I>::max();
    static constexpr I min = std::numeric_limits<I>::min();

    safe_int(I i) : val { i } { };

    safe_int &operator+=(I rhs)
    {
        if( val > 0 && rhs > max - val )
            throw std::overflow_error("");
        else if( val < 0 && rhs < min - val )
            throw std::underflow_error("");

        val += rhs;
        return *this;
    }
};
但很明显,如果在2的补码系统上输入
-0x8000000
,这将失败

然后我尝试这样做:

safe_int &operator-=(I rhs)
{
    return operator+=(-rhs);
}
safe_int &operator-=(I rhs)
{
    if(rhs < -max)
        throw std::overflow_error("");

    return operator+=(-rhs);
}
但现在,即使它正确地捕捉到可能发生溢出的情况,它本身也会在有效情况下导致溢出(例如,
-1--0x8000000
,其中
--0x8000000
溢出)

在这一点上,我相信在捕获所有关键情况的同时,无法重用来自加法的代码。因此,我可能应该为减法编写不同的代码

如何正确检查减法之前不会发生整数溢出

下面是一个小测试程序:

int main(void)
{
    safe_int<int> i = -1;

    i -= -2147483648;

    return 0;
}
int main(无效)
{
安全系数i=-1;
i-=-2147483648;
返回0;
}
假设整数没有特定的大小。不要依赖未定义的行为

template<class I>
bool valid_add( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if( rhs > 0 && lhs > max - rhs ) return false;
  if( rhs < 0 && lhs < min - rhs ) return false;

  return true;
}
template<class I>
bool valid_subtract( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if ((rhs < 0) && (lhs > max + rhs)) return false;
  if ((rhs > 0) && (lhs < min + rhs)) return false;

  return true;
}

如果不在整数类型上使用此代码,则需要更改此代码。在浮点类型上,有更多的复杂性


检查操作是否有效后,只需执行该操作即可。不要调用另一个函数。

有一些特殊的指令(加法、减法、乘法)通知溢出,但我怀疑是否有任何可移植的指令。您可以尝试查找它们。@ALX23z在检查溢出之前,您可以看出我没有使用汇编,也没有添加。我希望这是完全可移植的。我知道这不是重点,但你检查过了吗?@Tarc我不使用Boost。这是一个痛苦的安装,并带来了一个巨大的图书馆的东西,否则将是简单的。是的,但至少它是策划,我认为,安全的数字是为了便于携带。也许值得一读,看看作者使用的技巧。第一个是下溢,第二个是上溢,对吗?@S.S.Anne我在上面的代码中有4个不同的边界检查,我不确定你说的第一个或第二个是什么意思。在某种意义上,传递最大值是溢出,传递最小值是下溢。我指的是第二个函数,它检查减法。@S.S.Anne然后是否。传递最大值是溢出,而不是下溢。将
lhs>max+rhs
重新排列为
lhs-rhs>max
,以查看测试的(不安全但数学上等效)版本。
template<class I>
bool valid_add( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if( rhs > 0 && lhs > max - rhs ) return false;
  if( rhs < 0 && lhs < min - rhs ) return false;

  return true;
}
template<class I>
bool valid_subtract( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if ((rhs < 0) && (lhs > max + rhs)) return false;
  if ((rhs > 0) && (lhs < min + rhs)) return false;

  return true;
}
if (!valid_add(val, rhs))
   throw "whatever";
if (!valid_subtract(val, rhs))
   throw "whatever";