如何在C中检查给定数字是偶数还是奇数?
使用modulo(%)运算符检查除以2时是否有余数:
if (x % 2) { /* x is odd */ }
有几个人批评我上面的回答说明使用x&1是"更快"或"更有效".我不相信这是事实.
出于好奇,我创建了两个简单的测试用例程序:
/* modulo.c */ #includeint main(void) { int x; for (x = 0; x < 10; x++) if (x % 2) printf("%d is odd\n", x); return 0; } /* and.c */ #include int main(void) { int x; for (x = 0; x < 10; x++) if (x & 1) printf("%d is odd\n", x); return 0; }
然后我用gcc 4.1.3在我的一台机器上编译了5次不同的时间:
没有优化标志.
用-O
随着-Os
用-O2
使用-O3
我检查了每个编译的汇编输出(使用gcc -S),发现在每种情况下,and.c和modulo.c的输出都是相同的(它们都使用了andl $ 1,%eax指令).我怀疑这是一个"新"功能,我怀疑它可以追溯到古代版本.我也怀疑任何现代(在过去20年制造)非晦涩的编译器,商业或开源,缺乏这样的优化.我会测试其他编译器,但目前我还没有.
如果其他人愿意测试其他编译器和/或平台目标,并得到不同的结果,我会非常有兴趣知道.
最后,无论实现的有符号整数的表示如何,标准都可以保证模数版本能够工作,无论整数是正数,负数还是零.按位和版本不是.是的,我意识到两个补码有点无处不在,所以这不是一个真正的问题.
你们是waaaaaaaay太高效了.你真正想要的是:
public boolean isOdd(int num) { int i = 0; boolean odd = false; while (i != num) { odd = !odd; i = i + 1; } return odd; }
重复一遍isEven
.
当然,这对负数不起作用.但凭借辉煌而牺牲......
使用位算术:
if((x & 1) == 0) printf("EVEN!\n"); else printf("ODD!\n");
这比使用除法或模数更快.
[笑话模式="开"]
public enum Evenness { Unknown = 0, Even = 1, Odd = 2 } public static Evenness AnalyzeEvenness(object o) { if (o == null) return Evenness.Unknown; string foo = o.ToString(); if (String.IsNullOrEmpty(foo)) return Evenness.Unknown; char bar = foo[foo.Length - 1]; switch (bar) { case '0': case '2': case '4': case '6': case '8': return Evenness.Even; case '1': case '3': case '5': case '7': case '9': return Evenness.Odd; default: return Evenness.Unknown; } }
[笑话模式="关闭"]
编辑:为枚举添加了令人困惑的值.
为了回应ffpf - 几年前我与一位同事的论点完全相同,答案是否定的,它不适用于负数.
C标准规定负数可以用3种方式表示:
2的补充
1的补充
标志和规模
像这样检查:
isEven = (x & 1);
将用于2的补码和符号和幅度表示,但不适用于1的补码.
但是,我相信以下内容适用于所有情况:
isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));
感谢ffpf指出文本框在我的不足之后正在吃掉所有内容!
一个不错的是:
/*forward declaration, C compiles in one pass*/ bool isOdd(unsigned int n); bool isEven(unsigned int n) { if (n == 0) return true ; // I know 0 is even else return isOdd(n-1) ; // n is even if n-1 is odd } bool isOdd(unsigned int n) { if (n == 0) return false ; else return isEven(n-1) ; // n is odd if n-1 is even }
请注意,此方法使用涉及两个函数的尾递归.如果你的编译器像Scheme编译器一样支持尾递归,它可以有效地实现(变成while/until循环).在这种情况下,堆栈不应该溢出!
一个数字即使,当除以2时,余数为0.如果除以2,则余数为1时,数字为奇数.
// Java public static boolean isOdd(int num){ return num % 2 != 0; } /* C */ int isOdd(int num){ return num % 2; }
方法很棒!
i % 2 == 0
我只想把它除以2,如果有一个0余数,它就是偶数,否则就是奇数.
使用模数(%)可以轻松实现.
例如.4%2 = 0因此4甚至5%2 = 1因此5是奇数
问题的另一个解决方案
(欢迎儿童投票)
bool isEven(unsigned int x) { unsigned int half1 = 0, half2 = 0; while (x) { if (x) { half1++; x--; } if (x) { half2++; x--; } } return half1 == half2; }
我会构建一个奇偶校验表(0甚至1,如果奇数)的整数表(所以可以进行查找:D),但是gcc不会让我创建这样大小的数组:
typedef unsigned int uint; char parity_uint [UINT_MAX]; char parity_sint_shifted [((uint) INT_MAX) + ((uint) abs (INT_MIN))]; char* parity_sint = parity_sint_shifted - INT_MIN; void build_parity_tables () { char parity = 0; unsigned int ui; for (ui = 1; ui <= UINT_MAX; ++ui) { parity_uint [ui - 1] = parity; parity = !parity; } parity = 0; int si; for (si = 1; si <= INT_MAX; ++si) { parity_sint [si - 1] = parity; parity = !parity; } parity = 1; for (si = -1; si >= INT_MIN; --si) { parity_sint [si] = parity; parity = !parity; } } char uparity (unsigned int n) { if (n == 0) { return 0; } return parity_uint [n - 1]; } char sparity (int n) { if (n == 0) { return 0; } if (n < 0) { ++n; } return parity_sint [n - 1]; }
所以让我们改为使用偶数和奇数的数学定义.
即使存在整数k使得n = 2k,整数n也是.
如果存在整数k使得n = 2k + 1,则整数n是奇数.
这是它的代码:
char even (int n) { int k; for (k = INT_MIN; k <= INT_MAX; ++k) { if (n == 2 * k) { return 1; } } return 0; } char odd (int n) { int k; for (k = INT_MIN; k <= INT_MAX; ++k) { if (n == 2 * k + 1) { return 1; } } return 0; }
设C-整数表示int
给定C编译中的可能值.(注意,C-integers是整数的子集.)
现在有人可能会担心,对于C-整数中的给定n,相应的整数k可能不存在于C-整数中.但是通过一点证明,可以证明对于所有整数n,| n | <= | 2n | (*),其中| n | 如果n为正,则为"n,否则为-n".换句话说,对于所有n个整数,至少有以下一个成立(事实上恰好是情况(1和2)或情况(3和4),但我不会在这里证明):
案例1:n <= 2n.
情况2:-n <= -2n.
情况3:-n <= 2n.
情况4:n <= -2n.
现在取2k = n.(如果n是偶数,那么确实存在,但我不会在这里证明.如果n even
不均匀,那么循环无法提前返回,所以无关紧要.)但这意味着k
类似的论证表明,如果n是奇数,则在C-整数中存在ak,使得n = 2k + 1.
因此,功能even
和odd
这里提出将正常工作为所有的C-整数.
// C# bool isEven = ((i % 2) == 0);