简单问题 - 在c++中,最简洁的方法是获取哪个数字(u0和u1)是最小的正数?(仍然有效)
我尝试的每种方法都涉及大量if语句或复杂的条件语句。
谢谢, 丹
这里是一个简单的例子:
bool lowestPositive(int a, int b, int& result)
{
//checking code
result = b;
return true;
}
lowestPositive(5, 6, result);
简单问题 - 在c++中,最简洁的方法是获取哪个数字(u0和u1)是最小的正数?(仍然有效)
我尝试的每种方法都涉及大量if语句或复杂的条件语句。
谢谢, 丹
这里是一个简单的例子:
bool lowestPositive(int a, int b, int& result)
{
//checking code
result = b;
return true;
}
lowestPositive(5, 6, result);
如果这些值是用二进制补码表示的,则
result = ((unsigned )a < (unsigned )b) ? a : b;
当作为无符号数处理时,二进制补码中的负数值比正数值大,因此这种方法可行。与Jeff的答案类似,这需要至少有一个值是正数。
return result >= 0;
result
的具体值并不重要。 - jfs我更喜欢清晰明了而不是紧凑简洁:
bool lowestPositive( int a, int b, int& result )
{
if (a > 0 && a <= b) // a is positive and smaller than or equal to b
result = a;
else if (b > 0) // b is positive and either smaller than a or a is negative
result = b;
else
result = a; // at least b is negative, we might not have an answer
return result > 0; // zero is not positive
}
a>0
但b<0
,这种方法就会失败。他的答案基本上是使用模板完成的,并且在第一个if()
中增加了额外的条件。 - Peter Cordesunsigned int mask = 1 << 31;
unsigned int m = mask;
while ((a & m) == (b & m)) {
m >>= 1;
}
result = (a & m) ? b : a;
return ! ((a & mask) && (b & mask));
编辑:我觉得这并不太有趣,所以我删除了它。但是再想一想,还是留在这里好玩:) 这可以被认为是Doug答案的倾倒版本 :)
可能会被评为“负分”,但只是为了好玩,这里展示一下没有任何比较的结果,因为比较是弱者的表现。:-)
bool lowestPositive(int u, int v, int& result)
{
result = (u + v - abs(u - v))/2;
return (bool) result - (u + v + abs(u - v)) / 2;
}
这是一个使用位操作技巧来查找min(x, y)
的快速解决方案。它是@Doug Currie的答案的修改版本,并受到该问题的答案的启发:查找最小正值
bool lowestPositive(int a, int b, int* pout)
{
/* exclude zero, make a negative number to be larger any positive number */
unsigned x = (a - 1), y = (b - 1);
/* min(x, y) + 1 */
*pout = y + ((x - y) & -(x < y)) + 1;
return *pout > 0;
}
例子:
/** gcc -std=c99 *.c && a */
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdbool.h>
void T(int a, int b)
{
int result = 0;
printf("%d %d ", a, b);
if (lowestPositive(a, b, &result))
printf(": %d\n", result);
else
printf(" are not positive\n");
}
int main(int argc, char *argv[])
{
T(5, 6);
T(6, 5);
T(6, -1);
T(-1, -2);
T(INT_MIN, INT_MAX);
T(INT_MIN, INT_MIN);
T(INT_MAX, INT_MIN);
T(0, -1);
T(0, INT_MIN);
T(-1, 0);
T(INT_MIN, 0);
T(INT_MAX, 0);
T(0, INT_MAX);
T(0, 0);
return 0;
}
输出:
5 6 : 5
6 5 : 5
6 -1 : 6
-1 -2 are not positive
-2147483648 2147483647 : 2147483647
-2147483648 -2147483648 are not positive
2147483647 -2147483648 : 2147483647
0 -1 are not positive
0 -2147483648 are not positive
-1 0 are not positive
-2147483648 0 are not positive
2147483647 0 : 2147483647
0 2147483647 : 2147483647
0 0 are not positive
我建议您将该函数重构为更简单的函数。此外,这可以让您的编译器更好地强制执行预期的输入数据。
unsigned int minUnsigned( unsigned int a, unsigned int b )
{
return ( a < b ) ? a : b;
}
bool lowestPositive( int a, int b, int& result )
{
if ( a < 0 && b < 0 ) // SO comments refer to the previous version that had || here
{
return false;
}
result = minUnsigned( (unsigned)a, (unsigned)b ); // negative signed integers become large unsigned values
return true;
}
bool lowestPositive(int a, int b, int& result)
{
if ( a < 0 and b < 0 )
return false
result = std::min<unsigned int>( a, b );
return true;
}
话虽如此,您提供的签名允许出现隐蔽的错误,因为很容易忽略此函数的返回值,甚至不记得必须检查返回值以确定结果是否正确。
您可能更喜欢以下一种方案,它使得成功结果不易被忽视:
boost::optional<int> lowestPositive(int a, int b)
{
boost::optional<int> result;
if ( a >= 0 or b >= 0 )
result = std::min<unsigned int>( a, b );
return result;
}
或者
void lowestPositive(int a, int b, int& result, bool &success)
{
success = ( a >= 0 or b >= 0 )
if ( success )
result = std::min<unsigned int>( a, b );
}
这里很多答案忽略了零不是正数的事实 :)
通过巧妙的类型转换和三目运算符:
bool leastPositive(int a, int b, int& result) {
result = ((unsigned) a < (unsigned) b) ? a : b;
return result > 0;
}
不那么可爱:
bool leastPositive(int a, int b, int& result) {
if(a > 0 && b > 0)
result = a < b ? a : b;
else
result = a > b ? a : b:
return result > 0;
}
template<class T>
inline
bool LowestPositive( const T a, const T b, T* result ) {
const bool b_is_pos = b > 0;
if( a > 0 && ( !b_is_pos || a < b ) ) {
*result = a;
return true;
}
if( b_is_pos ) {
*result = b;
return true;
}
return false;
}
还要注意接受的答案(由tvanfosson提供)是错误的。如果a为正且b为负,则失败(说“两者都不是正数”)。 (这是我添加单独答案的唯一原因--我没有足够的声誉添加评论。)
使用“魔数”-1 进行黑客攻击:
enum
{
INVALID_POSITIVE = -1
};
int lowestPositive(int a, int b)
{
return (a>=0 ? ( b>=0 ? (b > a ? a : b ) : INVALID_POSITIVE ) : INVALID_POSITIVE );
}
这不会假设数字为正数。