uint32_t diff = abs(num1 - num2);
bool isZeroOrOne = (diff == 0 || diff == 1);
或者仅仅为了检查所有可能的情况:
int32_t diff = num1 - num2;
bool isZeroOrOne = (diff == 0 || diff == 1 || diff == -1);
有更优化的方式吗?
int32_t diff = uint32_t(num1) - uint32_t(num2);
bool isZeroOrOne = diff >= -1 && diff <= 1;
(uint32_t)(num1 - num2 + 1) <= 2
,正如 Raymond Chen 所评论的那样。unsigned
是必需的,以避免由于整数溢出而导致未定义行为。或者在支持的编译器中使用 -fwrapv
。
在Godbolt上的演示。正如您所看到的,编译器将下面的函数编译成完全相同的指令
#include <cstdint>
bool diff1(int32_t num1, int32_t num2)
{
int32_t diff = uint32_t(num1) - uint32_t(num2);
return diff >= -1 && diff <= 1;
}
bool diff2(int32_t num1, int32_t num2)
{
int32_t diff = uint32_t(num1) - uint32_t(num2);
return (uint32_t)(diff - (-1)) <= (1 - (-1));
}
diff1(INT32_MAX, INT32_MIN)
返回 true... - Paul Hankinuint32_t diff = (uint32_t)num1 - (uint32_t)num2; return diff+1 <= 2;
是一种更好的实现方式,避免了未定义和实现定义的行为,但仍然无法正确处理 INT_MIN
和 INT_MAX
的情况。 - Paul Hankinint32_t
的范围。 - M.Mint32_t
的范围。 - M.Mint32_t
的范围。 - undefinedint32_t
值,包括INT32_MIN
和INT32_MAX
;int check_adjacent(int32_t num1, int32_t num2) {
return 1ULL + num1 - num2 <= 2;
}
尽管我对优化的评论,但我无论如何还是做了,至少是一个子集。要优化代码,您需要包含上下文。在我们这里的情况下,两个参数n32_1和n32_2的统计频率是多少? 最优解将首先处理最频繁出现的情况,这使我得出了最佳答案。
我展示了当两个参数都在INT_MIN到INT_MAX范围内随机时的最佳解决方案。考虑到我的迄今为止无瑕疵的记录,这些话可谓勇敢。
我断言首先要做的最好的事情是获取两个参数的差异。然后发现最常见的情况,即它们不属于有趣的空间。这样就得出了很好的答案:
int64_t d = (int64_t)n32_1 - (int64_t)n32_2;
if (d > 1 || d < -1)
return 0;
return 1;
对于 INT_MIN - INT_MAX、INT_MIN+1 - INT_MIN、1 - 0、0 - 1 等情况,它的行为是正确的。
bool bTrueIfDiffOneOrZero( int32_t n32_1, int32_t n32_2 ) {
int64_t bIs1or0, d, n1 = n32_1, n2 = n32_2;
bIs1or0 = (d = n1 - n2) ? ( d == 1 || d == -1 ? 1 : 0) : 1;
return bIs1or0;
}
还有其他可以做的改变,比如不要使用bIs1or0,只返回表达式。至于比较汇编,这对我来说是一项新技能。它很有趣,但由于未知原因,我得到了预测的溢出,所以我在这一点上认输。我认为像这样优化某个东西是一个错误,所以我不会试图在汇编级别上与其他答案进行比较。谢谢你的评论。
是的,phuclv的答案是可行的解决方案。它提供了一种更简洁和优化的方法来确定两个int32_t数字之间的差异是否为0或1。通过将num1和num2转换为uint32_t类型,它避免了整数溢出问题,并使用单个比较操作来确定差异是否在所需范围内。这种方法已经得到许多编译器的支持,并且可以有效地进行优化。因此,如果您想进一步优化代码以确定两个数字之间的差异是否为0或1,则可以考虑使用phuclv的代码作为更简洁和高效的选项。
然而,我有一个小问题,关于是否需要(int32_t)转换。由于最终结果需要与-1和1进行比较,我认为可能需要将结果转换回int32_t类型,但我不确定是否正确。
int32_t diff = (int32_t)((uint32_t)num1 - (uint32_t)num2);
bool isZeroOrOne = (diff >= -1 && diff <= 1);
num1
为INT_MIN
且num2
为INT_MAX
时,它产生1,而结果应该是0。 - Eric Postpischil(uint32_t)num1 - (uint32_t)num2
不会溢出,但是结果值可能不适合于int32_t
,因此将其转换回int32_t
并不能提供有效的解决方案。在开始时将其转换为int64_t
并将其用于算术和测试即可。如果无法这样做,并且想要将其限制为32位类型,则需要进行额外的测试以避免溢出或实现定义的转换。一旦有了可行的代码,就需要考虑性能问题。该问题要求快速检查。 - Eric Postpischil这适用于任意两个int32_t类型的n1和n2,包括INT32_MAX、INT32_MIN,不会溢出。返回值bIs1or0。
double d, bIs1or0 = (d = n1 - n2) ? (d == 1 ? 1 : 0) : 1;
n1 - n2
。对于某些输入,它会溢出,并将其分配给double
也无法解决这个问题,因为在溢出之前不会发生转换为double
。 - Eric Postpischiln1 - n2
从一开始就是错误的。对于某些输入,它会溢出,并且将其分配给double
类型也无法修复,因为在溢出之前并不会进行转换为double
类型。 - Eric PostpischilINT32_MIN - INT32_MAX
将产生1,这将触发错误的结果1而不是0。您可以通过先转换为double
来避免这种情况。然而,涉及到double
总体来说对性能来说不是一个好主意;整数和浮点数之间的转换通常不是非常快速的,而这个问题的重点是找到一个快速的解决方案。 - Eric PostpischilINT32_MIN - INT32_MAX
将产生1,而不是正确的结果0。您可以通过先转换为double
来避免这个问题。然而,涉及到double
本身对性能来说是一个不好的主意;整数和浮点数之间的转换通常不是非常快速的,而这个问题的重点是找到一个快速的解决方案。 - Eric PostpischilINT32_MIN - INT32_MAX
将产生1,而不是正确的结果0。您可以通过先转换为double
来避免这种情况。然而,涉及到double
本身对性能来说是一个不好的主意;整数和浮点数之间的转换通常不是很快,而这个问题的重点是找到一个快速的解决方案。 - undefined你的问题意味着你有两个连续的或者相同的数字。如果其中一个是偶数,另一个必须是奇数才能返回1。 看一下这个条件解决方案。
bool res = ((num1%2) && (!(num2%2))) ?
true : ((!(num1%2)) && (num2%2))) ? true : false;
干杯。
%2
转换为位掩码操作,所以它并没有看起来那么糟糕。但我仍然不明白这怎么可能是一个正确的解决方案,更快的就更不用说了。 - Mark Ransomuint32
转换为int32
的开销要小。@JeremyFriesner - Iman Abdollahzadeh
(uint32_t)(num1 - num2 + 1) <= 2
- Raymond Chen