如何实现无符号 abs(int)?

3
这似乎很简单,但我可能漏掉了什么,或者…没有办法做到?

第一次尝试:

unsigned abs(int value) { return value < 0 ? -value : value; }

不行,"-value"是未定义行为。这会被clang -fsanitize检测到,并且在激进的优化面前通常是不安全的(尽管我真的希望没有理智的编译器滥用这一点)。

好的。我们来转换成无符号数!

unsigned abs(int value) { return value < 0 ? -unsigned(value) : unsigned(value); }

不行,在MSVC中这会导致C4146警告。此外,由于在无符号值上定义了一元减,我认为这假定了有符号整数的二补码格式。

好的...

unsigned abs(int value) { return value < 0 ? ~unsigned(value) + 1 : unsigned(value); }

这似乎没有产生任何警告或未定义的行为,但当然仅适用于二补码整数。此外,它有点难以理解 - 需要一条注释来解释为什么不使用一些直截了当的东西...

是否真的可以实现上述功能而不触发UB或依赖于整数表示?在我对C失去所有剩余的希望之前,请告诉我答案是“是”。


你是在将有符号整数转换为无符号整数,还是需要一个以unsigned int作为参数的abs函数? - Thomas Matthews
0值代替负值怎么样? unsigned abs(int value) { return value < 0 ? 0-value : value; } - Alex Lop.
3
由于INT_MIN是一个边界情况,您可以直接明确处理它。这使得您可以清楚地处理该边界情况。 - chris
等等,所以你不满意-value是因为在无限精度数学中,-INT_MIN比INT_MAX更大(因此会导致未定义行为)。但是在这种情况下,你希望abs(INT_MIN)的结果是什么?在我看来,你应该选择第一种选项并接受abs(INT_MIN)是未定义行为,或者你应该抛出某种异常。 - Chris Beck
1
@n.m.,不!请仔细阅读问题和std::abs的文档。 - zeuxcg
显示剩余18条评论
2个回答

2
正确的方法是#2,但为了消除MSVC的警告,需要应用一种解决方法:
unsigned abs(int value) { return value < 0 ? 0 - unsigned(value) : unsigned(value); }

这是正确的原因在于,有符号到无符号的转换被定义为将2^N+v返回给负v; 对于无符号整数的一元减运算被定义为2^N-v; 因此,无论有符号整数的表示如何,该代码都可以正常地返回绝对值。

1
如果-value可能导致未定义的行为,则应该将其定义明确:
unsigned abs(int value) { return value < 0 ? 0-value : value; }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接