如何检查整数是偶数还是奇数? [关闭]

Posted

技术标签:

【中文标题】如何检查整数是偶数还是奇数? [关闭]【英文标题】:How do I check if an integer is even or odd? [closed] 【发布时间】:2010-09-14 17:25:51 【问题描述】:

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

【问题讨论】:

使用按位和 (&) 的版本比取模 (%) 的版本效率高得多。您应该更改您选择的正确答案。 不太重要 - 参数是一个常数。易于优化器 这也是可读性因素。 在嵌入式应用程序(我花费大部分编程时间的世界)中,一些处理器具有非常原始的算术单元,不能轻松地进行除法/模数运算。出于这个原因,我通常使用按位与方法来代替。但是,在现代台式机的 CPU 上,情况并非如此。 我从来没有发现模运算更容易理解。当我第一次需要确定偶数或奇数时,我首先想到的是按位掩码。这有点自然,因为我们倾向于手动执行此操作的方式是查看最低有效数字,看看它是在 0 2 4 6 8 还是 1 3 5 7 9 中。这直接转化为查看最低有效位以查看它是 0 还是 1。 【参考方案1】:

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

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

一些人批评了我上面的回答,说使用 x & 1 是“更快”或“更有效”。我不相信是这样的。

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

/* modulo.c */
#include <stdio.h>

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 <stdio.h>

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 年制造的)非神秘编译器,无论是商业的还是开源的,都缺乏这种优化。我会在其他编译器上进行测试,但目前没有可用的。

如果其他人愿意测试其他编译器和/或平台目标,并得到不同的结果,我很想知道。

最后,标准保证模版本可以工作,无论整数是正数、负数还是零,而不管实现对带符号整数的表示。按位与版本不是。是的,我意识到二进制补码无处不在,所以这不是一个真正的问题。

【讨论】:

这个问题专门询问了如何在 C 中完成,所以我在 C 中回答了这个问题,尽管 chu​​star 提到他们无法弄清楚如何在 Java 中完成。我没有声称或暗示这是一个 Java 答案,我不知道 Java。我想我刚刚得到了我的第一个反对票,并且对为什么感到困惑。哦,好吧。 我会说,如果 (x % 2 != 0) /* x 是奇数 */ ,但谁知道呢。也不懂java。 它获得了很多支持,以将其与按位运算符白痴区分开来,而无需花费我们的业力将它们否决。 我同意一切,除了一件事:我喜欢在概念上将整数和真值分开,所以我更喜欢写“if (x % 2 == 1)”。这对编译器来说是一样的,但对人类来说可能更清楚一些。此外,您可以在不将非零解释为真的语言中使用相同的代码。 我的基准?什么基准?我没有做任何基准测试。我检查了生成的汇编语言。这与 printf 完全无关。【参考方案2】:

你们太有效率了。你真正想要的是:

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。当然现在你会有一个可以查询的网络服务 您应该使用查找表来优化它。 我是个僧侣,必须为你的 6,999 声望 +1 进入新千年 这太棒了!我的老板告诉我,我们有一个客户很生气,因为他觉得他的企业许可证只提供了标准许可证。现在我们在我们的程序中添加了这个功能,仅仅因为它执行得更慢,他认为他的软件做了更多的工作!!!【参考方案3】:

使用位算术:

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

这比使用除法或模数要快。

【讨论】:

我认为说它比使用除法或模数更快是不公平的。 C 标准没有说明运算符的性能,任何体面的编译器都会为它们生成快速代码。我个人会选择传达我意图的成语,% 在这里似乎更合适 我更喜欢 (x & 1),因为它检查数字是否是偶数的方式与人们相同:检查最后一位数字是偶数还是奇数。在我看来,它比模数方法更能传达其意图。 (这并不重要。) 你说得对,我想这是主观的。尽管“偶数”的通常定义是“可被 2 整除的整数”,而不是“以 0、2、4、6 或 8 结尾的整数”。 :-) @TraumaPony - 对于 ANSI 标准 C 和早期 Java,取决于计算机系统。未指定有符号数使用什么表示形式——2 的补码、1 的补码、灰色编码等。但模数始终是模数 不适用于负数。有关详细信息,请参阅检查此答案:***.com/questions/160930/… 了解详细信息。【参考方案4】:

[笑话模式=“开”]

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;
  

[笑话模式=“关闭”]

编辑:向枚举添加了令人困惑的值。

【讨论】:

哇...这比 SCdF 的解决方案更疯狂!赞!没有upvote虽然......不能推荐这个。但是谢谢你的好笑! 这种方法的优点是它不仅仅适用于数字。此外,如果您替换此行: char bar = foo[foo.Length - 1];用这个: double bar = Char.GetNumericValue(foo[foo.Length - 1]);然后它将适用于任何数字系统。 错误报告:当 14.65 应该未知时,报告为奇数。 软件绝地,这是一个“功能”。 ;) TheSoftwareJedi:14.65 是我见过的最奇怪的整数之一。【参考方案5】:

回复ffpf - 几年前我和一位同事的论点完全相同,答案是,它不适用于负数。

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

2 的补码 1 的补码 符号和大小

像这样检查:

isEven = (x & 1);

适用于 2 的补码以及符号和幅度表示,但不适用于 1 的补码。

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

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

感谢 ffpf 指出文本框正在吃掉我小于字符之后的所有内容!

【讨论】:

我认为您的第二个代码示例缺少一些文本。 让我们赞美这些数字!【参考方案6】:

一个不错的是:

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

【讨论】:

这不能很好地处理 isOdd(0)。 我认为对于带有任何偶数值的 isOdd() 或带有任何奇数值的 isEven() 存在无限循环(带有尾递归)或堆栈溢出(无尾递归)。它仅以 true 结束。这又是停机问题。 哦,当然,不加评论地修复它,让我看起来像个白痴。没关系。 现在,您遇到了编译错误:在 isEven 中,并非所有代码路径都返回值。不,我实际上并没有尝试过这段代码,这是我脑子里的编译器在抱怨。 编译错误:并非所有路径都返回一个值 【参考方案7】:

一个数是偶数,如果除以二,余数是 0。一个数是奇数,如果,除以 2,余数是 1。

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


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

方法很棒!

【讨论】:

您的 Java 方法已损坏,因为 num % 2 == -1 表示负奇数。 这就是你对我投反对票的原因吗? 我对它投了反对票,因为你在 C 中的函数需要比它更多的字符来输入。 IE num % I 是 7 个字符,包括空格 IsOdd(I) 是 8 个字符。为什么要创建一个比仅仅执行操作更长的函数? @Kevin 在我看来,代码不是用字符来衡量的,而是用你编写它的时间来衡量的,包括思考+调试时间。 num % 2 比 isOdd 多花一毫秒的时间。现在将全球数字相加,您就损失了一年。 isOdd 也可以进行测试、验证并最终获得无错误认证(例如处理负数),其中 num % 2 - 一些开发人员总是会产生疑问并进行试验。好的代码是你不写的代码,只是重复使用......只是我的 2 美分。 @EranMedan,同样的逻辑也适用于用 IncrementByOne(i) 替换 i++,这同样是个坏主意。如果开发人员对 num % 2 的作用有疑问,我不希望他或她靠近我的代码。【参考方案8】:
i % 2 == 0

【讨论】:

【参考方案9】:

我会说只需将其除以 2,如果余数为 0,则为偶数,否则为奇数。

使用模数 (%) 可以轻松完成。

例如。 4 % 2 = 0 因此 4 是偶数 5 % 2 = 1 因此 5 是奇数

【讨论】:

【参考方案10】:

问题的另一种解决方案(欢迎孩子们投票)

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,并非在所有州都有效)。 @WillHartung“幸福翻滚”太棒了! :D【参考方案11】:

我会建立一个整数的奇偶校验表(如果奇数则为 0)(因此可以进行查找: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];

所以让我们改用偶数和奇数的数学定义。

一个整数 n 是即使存在一个整数 k 使得 n = 2k。

如果存在整数 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 整数表示给定 C 编译中int 的可能值。 (请注意,C 整数是整数的子集。)

现在人们可能会担心,对于给定的 C 整数中的 n,对应的整数 k 可能不存在于 C 整数中。但是通过一点证明,可以证明对于所有整数 n,|n|

案例 1:n

案例 2:-n

案例 3:-n

案例 4:n

现在取 2k = n。 (如果 n 是偶数,这样的 ak 确实存在,但我不会在这里证明它。如果 n 不是偶数,那么even 中的循环无论如何都无法提前返回,所以没关系。)但这意味着 k even 中是 C 整数,因此 k = 0 是 C 整数)。因此,如果 n 是偶数,则对于 C 整数中的 n,存在这样的 C 整数中的 k。

类似的论点表明,如果 n 是奇数,则存在一个 C 整数中的 k,使得 n = 2k + 1。

因此,此处介绍的函数 evenodd 将适用于所有 C 整数。

【讨论】:

我不是冒犯的意思,但这个答案的意义何在? i % 2 更小,可能更高效。 @GMan:但这更具确定性!这将正确检测所有边缘情况。 ... AND (!!!) 是正确的!!! 我不知道你是不是在开玩笑。 :X %2 适用于所有整数。 +1:我想说“好答案”,但我认为“有趣的答案”更合适。【参考方案12】:
// C#
bool isEven = ((i % 2) == 0);

【讨论】:

什么?那不是 C#!那是纯C! :-P 我会在它周围添加一个 WinForm 以使其成为纯 C#... @mateusza:通常当您在 C 中的某个大写字母或其他字母中看到“bool”时,它是 typedef#define 之类的。 @mateusza @David Thornley 在 C99 中 bool 是标准功能 (en.wikipedia.org/wiki/Stdbool.h) 谈论大量多余的括号...【参考方案13】:

这是一个答案 爪哇:

public static boolean isEven (Integer Number) 
    Pattern number = Pattern.compile("^.*?(?:[02]|8|(?:6|4))$");
    String num = Number.toString(Number);
    Boolean numbr = new Boolean(number.matcher(num).matches());
    return numbr.booleanValue();

【讨论】:

【参考方案14】:

试试这个:return (((a&gt;&gt;1)&lt;&lt;1) == a)

例子:

a     =  10101011
-----------------
a>>1 --> 01010101
a<<1 --> 10101010

b     =  10011100
-----------------
b>>1 --> 01001110
b<<1 --> 10011100

【讨论】:

你能解释一下吗?我对位运算符很陌生 右移再左移将使最后一位(最右边的位)归零。如果新数与原数相同,则表示原数的最后一位为0。所以是偶数。看看我更新的答案。 谢谢,我明白了 我不确定哪种方法更快。我没有尝试对它们进行基准测试。 这不是也将您最重要的位归零吗?某些语言中的无符号整数和大多数语言中的负整数的问题......【参考方案15】:

阅读这个相当有趣的讨论后,我记得我有一个真实的、时间敏感的函数,可以在主循环中测试奇数和偶数。这是一个整数幂函数,发布在 *** 的其他地方,如下所示。基准非常令人惊讶。至少在这个现实世界的函数中,取模速度较慢,而且明显如此。 需要 67% 的模数时间的获胜者是一个或 (|) 方法,并且在此页面的其他地方找不到。

static dbl  IntPow(dbl st0, int x)  
    UINT OrMask = UINT_MAX -1;
    dbl  st1=1.0;
    if(0==x) return (dbl)1.0;

    while(1 != x)   
        if (UINT_MAX == (x|OrMask))      //  if LSB is 1...    
        //if(x & 1) 
        //if(x % 2) 
            st1 *= st0;
            
        x = x >> 1;  // shift x right 1 bit...  
        st0 *= st0;
    
    return st1 * st0;

对于 3 亿次循环,基准时间如下。

3.962 |和掩码方法

4.851 & 方法

5.850% 方法

对于那些认为理论或汇编语言列表来解决此类争论的人来说,这应该是一个警示故事。霍拉旭,天地间的事情比你的哲学梦想的还要多。

【讨论】:

x &lt; 0 时,最好使用unsigned x 作为x = x &gt;&gt; 1; 是实现定义的行为。不清楚为什么xOrMask 的类型不同。很简单,可以使用while(x) 测试重写。 我想知道您使用哪个编译器对此进行基准测试,因为大多数编译器应该足够聪明,可以使用按位 &amp; 编译 % 2 案例。我刚刚对此进行了测试,结果完全一样(VS2015,Release builds with all optimizations, both x86 and x64)。接受的答案也为 GCC 说明了这一点(写于 2008 年)。 这篇文章的问题在于,在任何平台/编译器上,按位 orand 快的前提是极不可能的。即使有这样一个奇怪的平台/编译器组合(并且您既没有发布也没有发布用于执行基准测试的代码),取决于其他编译器的行为相同将是一个糟糕的优化赌注。所以,正如我所写,我想知道这是在哪个平台/编译器上测试的,因为我几乎可以肯定它没有被正确测量。 不是说你是骗子,只是非常肯定地声称你没有正确测量。无需称我为卡车司机,请阅读我的原始评论:我确实做了一个基准测试,结果正如预期的那样,在所有三种情况下都完全相同(确定性约为 3 sigma,之后每个测试运行 10 次,迭代 500.000.000 次)。如果你真的有很长的辉煌职业生涯,退后一步想想你的主张是否有意义,然后发布用于执行基准测试的实际代码。否则,帖子就是我认为的那样,只是测量错误。 Done.【参考方案16】:

这是与@RocketRoy 就his answer 讨论的后续内容,但它可能对任何想要比较这些结果的人有用。

tl;dr 据我所见,Roy 的方法 ((0xFFFFFFFF == (x | 0xFFFFFFFE)) 并没有像 mod 方法那样完全优化到 x &amp; 1,但实际上运行时间应该会变成在所有情况下都相等。

所以,首先我使用Compiler Explorer比较编译输出:

功能测试:

int isOdd_mod(unsigned x) 
    return (x % 2);


int isOdd_and(unsigned x) 
    return (x & 1);


int isOdd_or(unsigned x) 
    return (0xFFFFFFFF == (x | 0xFFFFFFFE));
   

带有 -O3 的 CLang 3.9.0:

isOdd_mod(unsigned int):                          # @isOdd_mod(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_and(unsigned int):                          # @isOdd_and(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

isOdd_or(unsigned int):                           # @isOdd_or(unsigned int)
        and     edi, 1
        mov     eax, edi
        ret

带有 -O3 的 GCC 6.2:

isOdd_mod(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_and(unsigned int):
        mov     eax, edi
        and     eax, 1
        ret

isOdd_or(unsigned int):
        or      edi, -2
        xor     eax, eax
        cmp     edi, -1
        sete    al
        ret

感谢 CLang,它意识到这三种情况在功能上是相同的。但是,Roy 的方法没有在 GCC 中进行优化,所以 YMMV。

与 Visual Studio 类似;检查这三个函数的反汇编版本 x64 (VS2015),我可以看到比较部分对于“mod”和“and”情况是相等的,而对于 Roy 的“or”情况来说则稍大:

// x % 2
test bl,1  
je (some address) 

// x & 1
test bl,1  
je (some address) 

// Roy's bitwise or
mov eax,ebx  
or eax,0FFFFFFFEh  
cmp eax,0FFFFFFFFh  
jne (some address)

但是,在运行实际基准测试以比较这三个选项(普通 mod、按位或、按位与)后,结果完全相等(同样,Visual Studio 2005 x86/x64,发布版本,未附加调试器)。

对于andmod 情况,发布程序集使用test 指令,而Roy 的情况使用cmp eax,0FFFFFFFFh 方法,但它经过大量展开和优化,因此在实践中没有区别。

我运行 20 次后的结果(i7 3610QM,Windows 10 电源计划设置为高性能):

[测试:普通模式 2] 平均时间:689.29 毫秒(相对差异:+0.000%) [测试:按位或]平均时间:689.63 毫秒(相对差异:+0.048%) [测试:按位和]平均时间:687.80 毫秒(相对差异:-0.217%)

这些选项之间的差异小于 0.3%,因此很明显组装在所有情况下都是相等的。

如果有人想尝试,这里是代码,但需要注意的是我只在 Windows 上测试过它(检查 #if LINUX 条件以获取 get_time 定义并在需要时实现它,取自 this answer)。

#include <stdio.h>

#if LINUX
#include <sys/time.h>
#include <sys/resource.h>
double get_time()

    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;

#else
#include <windows.h>
double get_time()

    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart / (double)f.QuadPart * 1000.0;

#endif

#define NUM_ITERATIONS (1000 * 1000 * 1000)

// using a macro to avoid function call overhead
#define Benchmark(accumulator, name, operation)  \
    double startTime = get_time(); \
    double dummySum = 0.0, elapsed; \
    int x; \
    for (x = 0; x < NUM_ITERATIONS; x++)  \
        if (operation) dummySum += x; \
     \
    elapsed = get_time() - startTime; \
    accumulator += elapsed; \
    if (dummySum > 2000) \
        printf("[Test: %-12s] %0.2f ms\r\n", name, elapsed); \


void DumpAverage(char *test, double totalTime, double reference)

    printf("[Test: %-12s] AVERAGE TIME: %0.2f ms (Relative diff.: %+6.3f%%)\r\n",
        test, totalTime, (totalTime - reference) / reference * 100.0);


int main(void)

    int repeats = 20;
    double runningTimes[3] =  0 ;
    int k;

    for (k = 0; k < repeats; k++) 
        printf("Run %d of %d...\r\n", k + 1, repeats);
        Benchmark(runningTimes[0], "Plain mod 2", (x % 2));
        Benchmark(runningTimes[1], "Bitwise or", (0xFFFFFFFF == (x | 0xFFFFFFFE)));
        Benchmark(runningTimes[2], "Bitwise and", (x & 1));
    

    
        double reference = runningTimes[0] / repeats;
        printf("\r\n");
        DumpAverage("Plain mod 2", runningTimes[0] / repeats, reference);
        DumpAverage("Bitwise or", runningTimes[1] / repeats, reference);
        DumpAverage("Bitwise and", runningTimes[2] / repeats, reference);
    

    getchar();

    return 0;

【讨论】:

我相信你犯了基准测试的大罪;创建一个如此具体的它并不代表真实世界的环境。查看您的汇编语言并注意您使用的寄存器数量。努力的高分,但这些结果在现实世界的处理中是站不住脚的。 @RocketRoy:因为所有三种情况下的所有输出都完全相同(好吧,在一种情况下,您的程序稍微差一点),我真的不在乎使用了多少寄存器。但同样,请随意创建和发布这样的示例程序/环境,这会使编译器在其中一种情况下创建更优化的程序集时感到困惑,所有其他条件都相同。 我一直喜欢自大的程序员。对于程序员来说这是一个很好的特性,但是在更复杂的真实程序中,我的方法会比你的方法执行得更好,因为编译器有更多的方法来解决问题,因此指令重叠(在英特尔架构上)会产生更好的结果.很少有具有良好基准测试经验的资深程序员会喜欢您的基准测试,但请继续努力,并记住在新芯片发布时重新运行您的基准测试。事情确实会随着时间而改变。【参考方案17】:

我知道这只是语法糖,仅适用于 .net,但是扩展方法呢...

public static class RudiGroblerExtensions

    public static bool IsOdd(this int i)
    
        return ((i % 2) != 0);
    

现在您可以执行以下操作

int i = 5;
if (i.IsOdd())

    // Do something...

【讨论】:

不错的代码。可惜它会声称 2 是奇数,而 3 不是。 哎呀,对不起...我的逻辑错了...【参考方案18】:

在我提供的“创意但令人困惑的类别”中:

int isOdd(int n)  return n ^ n * n ? isOdd(n * n) : n; 

此主题的变体,特定于 Microsoft C++:

__declspec(naked) bool __fastcall isOdd(const int x)

    __asm
    
        mov eax,ecx
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        mul eax
        ret
    

【讨论】:

【参考方案19】:

按位方法取决于整数的内部表示。模数将在任何有模数运算符的地方工作。例如,某些系统实际上使用低级位进行标记(如动态语言),因此原始 x & 1 在这种情况下实际上不起作用。

【讨论】:

【参考方案20】:

IsOdd(int x) 返回真;

正确性证明 - 考虑所有正整数的集合,并假设有一个非空整数集合不是奇数。因为正整数是有序的,所以会有一个最小的非奇数,它本身就很奇数,所以很明显这个数字不可能在集合中。因此这个集合不能是非空的。重复负整数,除了寻找最大的非奇数。

【讨论】:

【参考方案21】:

便携:

i % 2 ? odd : even;

不可移植:

i & 1 ? odd : even;

i << (BITS_PER_INT - 1) ? odd : even;

【讨论】:

【参考方案22】:

正如一些人所发布的,有很多方法可以做到这一点。根据this website,最快的方法是取模操作:

if (x % 2 == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

但是,这里有一些作者的other code that was bench marked,它的运行速度比上面的普通模运算要慢:

if ((x & 1) == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

System.Math.DivRem((long)x, (long)2, out outvalue);
        if ( outvalue == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x / 2) * 2) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

if (((x >> 1) << 1) == x)
               total += 1; //even number
        else
               total -= 1; //odd number

        while (index > 1)
               index -= 2;
        if (index == 0)
               total += 1; //even number
        else
               total -= 1; //odd number

tempstr = x.ToString();
        index = tempstr.Length - 1;
        //this assumes base 10
        if (tempstr[index] == '0' || tempstr[index] == '2' || tempstr[index] == '4' || tempstr[index] == '6' || tempstr[index] == '8')
               total += 1; //even number
        else
               total -= 1; //odd number

有多少人甚至知道Math.System.DivRem 方法或者他们为什么要使用它??

【讨论】:

【参考方案23】:
int isOdd(int i)
  return(i % 2);

完成。

【讨论】:

你的笑话给出了错误的答案。【参考方案24】:

为了给我们这些在学习期间没有做太多布尔代数的人详细说明按位运算符方法,这里有一个解释。可能对 OP 没有多大用处,但我想弄清楚为什么 NUMBER & 1 有效。

请注意,就像上面有人回答的那样,表示负数的方式可能会停止此方法的工作。事实上,它甚至可以破坏模运算符方法,因为每种语言在处理负操作数的方式上可能不同。

但是,如果您知道 NUMBER 将始终为正数,则效果很好。

正如上面的 Tooony 所指出的,只有二进制(和拒绝)中的最后一个数字很重要。

布尔逻辑与门规定两个输入都必须为 1(或高电压)才能返回 1。

1 & 0 = 0。

0 & 1 = 0。

0 & 0 = 0。

1 & 1 = 1。

如果您将任何数字表示为二进制(我在这里使用了 8 位表示),奇数的末尾为 1,偶数的末尾为 0。

例如:

1 = 00000001

2 = 00000010

3 = 00000011

4 = 00000100

如果您取任何数字并使用按位与(Java 中的 &)乘以 1,它将返回 00000001,= 1 表示该数字是奇数。或者00000000 = 0,表示这个数是偶数。

例如

奇怪吗?

1 & 1 =

00000001 &

00000001 =

00000001

2 & 1 =

00000010 &

00000001 =

00000000

54 & 1 =

00000001 &

00110110 =

00000000

这就是它起作用的原因:

if(number & 1)

   //Number is odd

 else 

   //Number is even

对不起,如果这是多余的。

【讨论】:

【参考方案25】:

数字零奇偶校验 |零http://tinyurl.com/oexhr3k

Python 代码序列。

# defining function for number parity check
def parity(number):
    """Parity check function"""
    # if number is 0 (zero) return 'Zero neither ODD nor EVEN',
    # otherwise number&1, checking last bit, if 0, then EVEN, 
    # if 1, then ODD.
    return (number == 0 and 'Zero neither ODD nor EVEN') \
            or (number&1 and 'ODD' or 'EVEN')

# cycle trough numbers from 0 to 13 
for number in range(0, 14):
    print "0:>4 : 0:08b : 1:".format(number, parity(number))

输出:

   0 : 00000000 : Zero neither ODD nor EVEN
   1 : 00000001 : ODD
   2 : 00000010 : EVEN
   3 : 00000011 : ODD
   4 : 00000100 : EVEN
   5 : 00000101 : ODD
   6 : 00000110 : EVEN
   7 : 00000111 : ODD
   8 : 00001000 : EVEN
   9 : 00001001 : ODD
  10 : 00001010 : EVEN
  11 : 00001011 : ODD
  12 : 00001100 : EVEN
  13 : 00001101 : ODD

【讨论】:

@el.pescado,谢谢。如果零是偶数,它有多少对? @el.pescado,好的,我同意你的看法。那么,如果稍微想一想,为什么我们划分为 2(二)?当我们一分为二时,我们想知道什么?为什么不分成 3 或 5 等? @el.pescado 这篇***文章Parity of Zero 是错误的。很多人都被这篇文章骗了。在眨眼之前思考。 你是对的。现在我已经阅读了其他答案,我发现你的答案最全面:) @el.pescado。谢谢。 :) 现在你是 Zero 最好的朋友了。 (拥抱)【参考方案26】:
I execute this code for ODD & EVEN:

#include <stdio.h>
int main()

    int number;
    printf("Enter an integer: ");
    scanf("%d", &number);

    if(number % 2 == 0)
        printf("%d is even.", number);
    else
        printf("%d is odd.", number);

【讨论】:

【参考方案27】:

为了讨论……

您只需要查看任何给定数字中的最后一位数字,看看它是偶数还是奇数。 有符号的、无符号的、正的、负的——在这方面它们都是一样的。 所以这应该全面工作:-

void tellMeIfItIsAnOddNumberPlease(int iToTest)
  int iLastDigit;
  iLastDigit = iToTest - (iToTest / 10 * 10);
  if (iLastDigit % 2 == 0)
    printf("The number %d is even!\n", iToTest);
   else 
    printf("The number %d is odd!\n", iToTest);
  

这里的关键是在第三行代码中,除法运算符执行整数除法,所以结果中缺少小数部分。因此,例如 222 / 10 将给出 22 作为结果。然后再乘以 10,得到 220。从原来的 222 中减去,最后得到 2,这与原始数字中的最后一位数字相同。 ;-) 括号用来提醒我们计算的顺序。首先进行除法和乘法运算,然后从原始数字中减去结果。我们可以忽略它们,因为除法和乘法的优先级高于减法,但这给了我们“更易读”的代码。

如果我们愿意,我们可以让它完全不可读。对于现代编译器来说,这没有任何区别:-

printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");

但这会使代码在未来更难维护。想象一下,您想将奇数的文本更改为“不是偶数”。然后其他人稍后想找出您所做的更改并执行 svn diff 或类似...

如果您不担心可移植性,而更关注速度,您可以查看最低有效位。如果该位设置为 1,则为奇数,如果为 0,则为偶数。 在小端系统上,比如 Intel 的 x86 架构,它会是这样的:-

if (iToTest & 1) 
  // Even
 else 
  // Odd

【讨论】:

只使用 iToTest%2==0 到底有什么问题?您正在浪费一个除法来提取最后一位数字,因此您的速度是所需速度的两倍。 @freespace:我浪费的不止这些,不是吗? :-) 也是乘法和减法。但是我不敢说这两种解决方案之间最有效的是什么。从未声称这是最快的解决方案,如果您再次阅读我的帖子的第一行,则完全相反。 @Tooony,啊,我的幽默帽子掉了。它现在正式恢复了:D 抱歉 :)【参考方案28】:

如果您想提高效率,请使用按位运算符 (x &amp; 1),但如果您想可读,请使用模 2 (x % 2)

【讨论】:

-1:如果您想提高效率,请使用其中之一。如果您希望它是可移植的,请使用%。如果您希望它可读,请使用%。嗯,我在这里看到了一个模式。 @trinithis,没有模式,这个解决方案比你的好得多。【参考方案29】:

检查偶数或奇数是一项简单的任务。

我们知道任何能被 2 整除的数都是偶数,否则是奇数。

我们只需要检查任意数的可分性,我们使用%运算符来检查可分性

使用 if else 检查奇偶数

if(num%2 ==0)  

    printf("Even");

else

    printf("Odd");

C program to check even or odd using if else

使用条件/三元运算符

(num%2 ==0) printf("Even") : printf("Odd");

C program to check even or odd using conditional operator。

使用位运算符

if(num & 1)  

    printf("Odd");

else 

    printf("Even");

【讨论】:

三元运算符到底在哪里?【参考方案30】:

+66% 更快 > !(i%2) / i%2 == 0

int isOdd(int n)

    return n & 1;

代码检查整数的最后一位是否为二进制1

说明

Binary  :   Decimal
-------------------
0000    =   0
0001    =   1
0010    =   2
0011    =   3
0100    =   4
0101    =   5
0110    =   6
0111    =   7
1000    =   8
1001    =   9
and so on...

注意对于奇数数,最右边的总是1。

& 位 AND 运算符检查 return 行中最右边的位是否为 1

认为它是真假

当我们将 n1 进行比较时,这意味着 0001 二进制(零的数量无关紧要)。 那么让我们想象一下,我们有一个大小为 1 字节的整数 n

它将由 8 位/8 位二进制数字表示。

如果 int n7,我们将其与 1 进行比较,就像

7 (1-byte int)|    0  0  0  0    0  1  1  1
       &
1 (1-byte int)|    0  0  0  0    0  0  0  1
********************************************
Result        |    F  F  F  F    F  F  F  T

其中F代表假,T代表真。

比较只有最右边的位如果它们都是真的。所以,7 &amp; 1 自动是 True。

如果我想检查最右边的位怎么办?

只需将n &amp; 1 更改为n &amp; 2,其中2 代表二进制中的0010,依此类推。

如果您是按位运算的初学者,我建议使用十六进制表示法return n &amp; 1; >> return n &amp; 0x01;

【讨论】:

以上是关于如何检查整数是偶数还是奇数? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C程序检查数字是偶数还是奇数

PHP 如何检查数字是奇数还是偶数

如何检查一个数字是奇数还是偶数

如何检查循环计数? (以及它是偶数还是奇数)[重复]

输入一个整数判断是奇数还是偶数,C语言程序

判断一个数是奇数还是偶数用C程序怎么编写