【问题标题】:Check if the sum of two unsigned ints is larger than uint_max检查两个无符号整数之和是否大于 uint_max
【发布时间】:2018-02-28 08:03:40
【问题描述】:

假设我有两个整数xy,我想检查它们的总和是否大于UINT_MAX

#define UINT64T_MAX std::numeric_limits<uint64_t>::max()

uint64_t x = foo();
uint64_t y = foo();
bool carry = UINT64T_MAX - x < y;

该代码可以工作,但我想知道是否有更有效的方法来做到这一点 - 可能使用 CPU 具有的一些鲜为人知的功能。

【问题讨论】:

  • 数值有什么限制吗?最小/最大?任何事物? (如果是这样,您可能会将其降低为 1 个比较)在一般情况下,减法还不错,也许您可​​以使用位掩码来确定两个数字 ANDED 一起是否会创建 UINT64T_MAX,按位运算非常便宜,但我不'不知道 AND 会正确解释溢出。
  • 标题写着unsigned ints 和uint_max,但代码写着uint64_t。你到底是什么意思?
  • 如果有一个“鲜为人知的 CPU 特性”,那么你的编译器应该知道它
  • @M.M 没错,但编译器并不神奇——您确实需要“不阻止”它们应用任何给定的优化。参见“好像”规则。

标签: c++ integer unsigned-integer


【解决方案1】:

在 C++ 中,无符号整数溢出具有明确定义的行为。如果将两个无符号整数相加,结果小于任何一个,则计算溢出。 (结果总是比两者都小,所以你检查哪一个并不重要。)

#define UINT64T_MAX std::numeric_limits<uint64_t>::max()

uint64_t x = foo();
uint64_t y = foo();
uint64_t z = x + y;
bool carry = z < x;

我相信这是在可移植、定义明确的 C++ 中实现此目的的最佳方式。 Clang 和 GCC 都将这个简单的示例编译为两个 amd64 指令的最佳序列 (add x, y; setc carry)。

概括为有符号整数溢出,因为有符号整数溢出是未定义的行为(尽管some C++ committee members are looking to change that)。

一些编译器在各种算术函数之后提供non-standard ways to check for overflow,不仅用于加法,也不仅仅用于有符号数。如果您可以承受失去可移植性的代价,那么将它们用于添加的功能可能值得研究。对于无符号加法溢出的特定情况,在某些不平凡的情况下,性能可能相同或快得可以忽略不计,并且可能不值得失去可移植性。

【讨论】:

  • 是我所拥有的,但 OP 想检查它是否受 INT_MAX 限制;即大约一半 UINT_MAX。
  • OP 用英文说的和 OP 用代码说的不一样。
  • 其实我的意思是 UINT_MAX。
  • 不是第一次规范与代码不匹配 ;-)
  • 当 gcc 看到你的 x+y
【解决方案2】:
auto t = x + y;
bool x_y_overflows_unsigned = t < x || t < y; // Actually, the second check is unnecessary.

将很难被击败,并且可能更清楚,因为使用无符号类型的减法通常会引入错误。

但如果您有任何疑问,请检查生成的程序集。

【讨论】:

  • @MarcGlisse:他们这样做了,即将投票赞成这个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 2016-03-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 2017-12-26
  • 1970-01-01
相关资源
最近更新 更多