当前位置:  开发笔记 > 编程语言 > 正文

如何检查整数是偶数还是奇数?

如何解决《如何检查整数是偶数还是奇数?》经验,为你挑选了12个好方法。

如何在C中检查给定数字是偶数还是奇数?



1> Chris Young..:

使用modulo(%)运算符检查除以2时是否有余数:

if (x % 2) { /* x is odd */ }

有几个人批评我上面的回答说明使用x&1是"更快"或"更有效".我不相信这是事实.

出于好奇,我创建了两个简单的测试用例程序:

/* modulo.c */
#include 

int 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年制造)非晦涩的编译器,商业或开源,缺乏这样的优化.我会测试其他编译器,但目前我还没有.

如果其他人愿意测试其他编译器和/或平台目标,并得到不同的结果,我会非常有兴趣知道.

最后,无论实现的有符号整数的表示如何,标准都可以保证模数版本能够工作,无论整数是正数,负数还是零.按位和版本不是.是的,我意识到两个补码有点无处不在,所以这不是一个真正的问题.


我的基准?什么基准?我没有做任何基准测试.我检查了生成的汇编语言.这与printf完全无关.
我会说,if(x%2!= 0){/*x是奇数*/},但是谁知道.也不知道java.
我同意一切,除了一件事:我喜欢将整数和真值分开,从概念上讲,所以我更喜欢写"if(x%2 == 1)".这对编译器来说是一样的,但对人类来说可能更清楚一点.另外,您可以在不将非零解释为真的语言中使用相同的代码.
这个问题具体问到了如何在C中做到这一点,所以我在C中回答了它,尽管chustar提到他们无法解决如何用Java做到这一点.我没有声称或暗示这是一个Java答案,我不懂Java.我想我刚刚得到了我的第一个downvote并且为什么而感到困惑.那好吧.
它得到了许多赞成,以区别于按位运算符的蠢货,而不必花费我们的业力投票.
如果/当这样的优化既正确又快速时,现代编译器将x%2优化为x&1.在过去,它可能不正确(1的恭维系统),现在是一天,它不太可能更快(所有算术在1个周期内完成).
"两个补充有点无处不在"?你怎么能无处不在,但"有点"?
林健:无处不在意味着它无处不在,所以我用"有点无处不在"来表示它几乎发生在各处.对不起,如果不清楚.

2> SCdF..:

你们是waaaaaaaay太高效了.你真正想要的是:

public boolean isOdd(int num) {
  int i = 0;
  boolean odd = false;

  while (i != num) {
    odd = !odd;
    i = i + 1;
  }

  return odd;
}

重复一遍isEven.

当然,这对负数不起作用.但凭借辉煌而牺牲......


您应该使用查找表对其进行优化.
如果你在负值上抛出一个参数异常,并在文档中注明该函数是O(N),那么我就可以了.
企业版必须使用XML.当然,现在您可以使用可以查询的Web服务
这太棒了!我的老板告诉我,我们有一个生气的客户,因为他觉得他的企业许可证没有提供比标准许可证更多的东西.现在我们已经在我们的程序中添加了这个功能,只是因为它执行得更慢,他认为他的软件正在做更多的工作!

3> Adam Pierce..:

使用位算术:

if((x & 1) == 0)
    printf("EVEN!\n");
else
    printf("ODD!\n");

这比使用除法或模数更快.


我认为说它比使用除法或模数更快是不公平的.C标准没有说明运算符的性能,任何体面的编译器都会生成快速代码.我会亲自选择传达我意图的成语,而%似乎更合适
我更喜欢(x&1),因为它检查数字是否与人们的方式相同:检查最后一位是偶数还是奇数.在我看来,它传达的意图不仅仅是模数方法.(这不重要.)
对于负数不起作用.有关详细信息,请参阅此答案以获取更多详细信息:http://stackoverflow.com/questions/160930/how-do-i-check-if-an-integer-is-even-or-odd#161326.
@TraumaPony - 对于ANSI标准C和早期Java,取决于计算机系统.未指定用于签名数字的表示形式 - 2的恭维,1的恭维,灰色编码等.但模数总是模数
你是对的,我想这是主观的.虽然"偶数​​"的通常定义是"可被2整除的整数",但不是"以0,2,4,6或8结尾的整数".:-)
bleh,牺牲明确的"聪明"意图.谈论过早优化......
位掩码解决方案取决于数字的内部表示.虽然今天通常使用Two's补充,但没有给出,它在未来仍然存在.因此,使用模运算符,您的代码始终是正确的.好的编译器无论如何都要优化它.
请注意,此方法需要了解手头类型的内部结构,而模数则不需要.
是的,不适用于1的补码数.

4> Sklivvz..:

[笑话模式="开"]

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;
  }
}

[笑话模式="关闭"]

编辑:为枚举添加了令人困惑的值.


TheSoftwareJedi:14.65是我见过的最奇怪的整数之一.
错误报告:14.65报告为奇数,应该是未知的.
软件绝地,这是一个"功能".;)
哇......这比SCdF的解决方案更让人沮丧!奖励!没有upvote虽然...不能推荐这个.但感谢有趣!

5> Andrew Edgec..:

为了回应ffpf - 几年前我与一位同事的论点完全相同,答案是否定的,它不适用于负数.

C标准规定负数可以用3种方式表示:

2的补充

1的补充

标志和规模

像这样检查:

isEven = (x & 1);

将用于2的补码和符号和幅度表示,但不适用于1的补码.

但是,我相信以下内容适用于所有情况:

isEven = (x & 1) ^ ((-1 & 1) | ((x < 0) ? 0 : 1)));

感谢ffpf指出文本框在我的不足之后正在吃掉所有内容!


让我们赞美这些数字吧!

6> Pierre..:

一个不错的是:

/*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循环).在这种情况下,堆栈不应该溢出!


哦,当然,修理它没有评论,让我看起来像个白痴.没关系.
编译错误:并非所有路径都返回一个值讨厌你用示例代码中的bug注释轰炸你,但是当你调用isEven时会发生什么(5)

7> jjnguy..:

一个数字即使,当除以2时,余数为0.如果除以2,则余数为1时,数字为奇数.

// Java
public static boolean isOdd(int num){
    return num % 2 != 0;
}

/* C */
int isOdd(int num){
    return num % 2;
}

方法很棒!


@Kevin在我看来,代码不是由字符来衡量,而是由你编写它的时间来衡量,包括思考+调试时间.num%2比isOdd更需要一毫秒.现在全局添加数字,你失去了一个集体年份.也是isOdd可以进行测试,并经过验证并最终获得无错误认证(例如处理负数),其中num%2 - 一些开发人员总会怀疑并进行实验.好的代码是你不写的代码,只是重用...只需要我的2美分.
我贬低它是因为你在C中的函数需要更多的字符来输入它.IE num%I是7个字符,包括空格IsOdd(I)是8个字符.为什么要创建一个比执行操作更长的函数?
@EranMedan,相同的逻辑适用于用IncrementByOne(i)替换i ++,这也是一个不错的主意.如果开发人员对num%2的作用有疑问,我不希望他或她在我的代码附近.

8> Mark Cidade..:
i % 2 == 0



9> Jarod Elliot..:

我只想把它除以2,如果有一个0余数,它就是偶数,否则就是奇数.

使用模数(%)可以轻松实现.

例如.4%2 = 0因此4甚至5%2 = 1因此5是奇数



10> eugensk..:

问题的另一个解决方案
(欢迎儿童投票)

bool isEven(unsigned int x)
{
  unsigned int half1 = 0, half2 = 0;
  while (x)
  {
     if (x) { half1++; x--; }
     if (x) { half2++; x--; }

  }
  return half1 == half2;
}


所有数字都是明亮而积极的.或者你对某些人有偏见吗?:))
在计算机中,所有数字一旦消极,最终变为正数.我们称之为幸福的滚动(不适用于BIGNUMS,YMMY,在所有州都无效).

11> Thomas Eding..:

我会构建一个奇偶校验表(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 even,因此k = 0是C-整数).因此,如果n是偶数,则C-整数中的n存在于C-整数中的n.

类似的论证表明,如果n是奇数,则在C-整数中存在ak,使得n = 2k + 1.

因此,功能evenodd这里提出将正常工作为所有的C-整数.


@GMan:但这更确定了!这将正确检测所有边缘情况.

12> Michael Petr..:
// C#
bool isEven = ((i % 2) == 0);


我会在它周围抛出一个WinForm来使它成为纯粹的C#...
纯C中的bool?
什么?那不是C#!那是纯粹的C!:-P
@mateusza @David Thornley在C99 bool是一个标准功能(http://en.wikipedia.org/wiki/Stdbool.h)
推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有