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


193

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


5
使用按位和(&)的版本比取模(%)版本的效率要高得多。您应该更改选择为正确答案的那个。
Stefan Rusek,

6
无关紧要-参数是一个常数。轻松进行优化程序
MSalters

2
可读性也是这一因素。
布赖恩·G

2
在嵌入式应用程序中(我花了大部分时间在世界上),某些处理器具有非常原始的算术单元,无法轻松进行除法/模运算。因此,我通常使用按位与方法。但是,在现代台式机的CPU上并非如此。
bta 2010年

3
我从未发现模数运算更容易理解。当我第一次需要确定偶数或奇数时,首先想到的是按位掩码。这有点自然,因为我们倾向于手动执行此操作的方式是查看最低有效数字以查看它是否位于{0 2 4 6 8}或{1 3 5 7 9}中。这直接转化为看至少显著位,看它是否是0或1
P爸爸

Answers:


449

使用模(%)运算符检查除以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年来制造的)非arcane编译器,无论是商业的还是开源的,都缺乏这种优化。我会在其他编译器上进行测试,但目前没有任何可用。

如果其他人愿意测试其他编译器和/或平台目标并获得不同的结果,我将非常感兴趣。

最后,标准保证了模版本可以工作,无论整数是正数,负数还是零,无论实现方式是有符号整数的表示形式。按位和版本不是。是的,我知道二进制补码在某种程度上是无处不在的,因此这并不是真正的问题。


11
这个问题专门询问了如何在C语言中进行操作,因此尽管chustar提到他们无法解决如何在Java中进行操作,但我还是用C语言回答了该问题。我没有声称或暗示这是Java的答案,我不知道Java。我想我只是第一次投票,对为什么感到困惑。那好吧。
克里斯·杨

33
我会说,如果(x%2!= 0){/ * x是奇数* /,但是谁知道。也不懂Java。
欧根斯克

9
可以将其与按位操作符白痴区分开来,而无需花费我们的业力将其否决,这得到了很多支持。
08年

13
我同意所有内容,除了一件事:从概念上讲,我喜欢将整数和真值分开,因此我更喜欢写“ if(x%2 == 1)”。对于编译器来说是相同的,但是对于人类来说可能更清晰一些。另外,您可以在不会将非零解释为true的语言中使用相同的代码。
Thomas Padron-McCarthy

46
我的基准?什么基准?我没有做任何基准测试。我检查了生成的汇编语言。这与printf绝对无关。
克里斯·杨

207

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

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

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

  return odd;
}

重复isEven

当然,这不适用于负数。但是光彩照人牺牲了...


17
如果您对负值抛出参数异常,并在文档中指出此函数为O(N),那么我会很好用。
Jeffrey L Whitledge,

7
企业版将必须使用XML。当然,如今您将拥有可以查询的Web服务
Martin Beckett

58
您应该使用查找表对此进行优化。
Weeble

1
我真是个和尚,必须为您的6,999名代表+1进入新的千年
Eran Medan 2012年

7
这太棒了!我的老板告诉我,我们有一个客户很生气,因为他觉得他的企业许可证没有提供比标准许可证更多的东西。现在,我们在程序中添加了此功能,仅仅因为执行速度较慢,他认为他的软件正在做更多的工作!!!
Phil

97

使用位运算:

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

这比使用除法或模量更快。


43
我认为说它比使用除法或模数更快是不公平的。C标准没有说明运算符的性能,任何不错的编译器都会为其中任何一个生成快速代码。我会亲自选择表达我意图的惯用语,此处%似乎更合适
克里斯·杨

21
我更喜欢(x&1),因为它可以检查数字是否与人们的用法相同:检查最后一位数字是偶数还是奇数。在我看来,它传达的意图不只是取模方法。(并不是很重要。)
杰里米·鲁滕

2
您说得对,我想这是主观的。尽管“偶数”的通常定义是“可被2整除的整数”,而不是“以0、2、4、6或8结尾的整数”。:-)
克里斯·杨

4
@TraumaPony-对于ANSI标准C和早期的Java,取决于计算机系统。对于带符号的数字,使用哪种表示形式(2的恭维,1的恭维,灰色编码等),目前尚不确定。但是模数始终是模数
Aaron

9
不适用于负数。请参阅检查此答案以获取更多详细信息:stackoverflow.com/questions/160930/…了解详细信息。
Andrew Edgecombe

36

[笑话模式=“开启”]

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

[笑话模式=“关闭”]

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


2
哇...这比SCdF的解决方案更痴迷!荣誉!尽管没有投票...不能推荐此举。但是,谢谢您的搞笑!
Wes P

1
这种方法的优点是它不仅可以处理数字。另外,如果替换此行:char bar = foo [foo.Length-1]; 这样:double bar = Char.GetNumericValue(foo [foo.Length-1]); 然后它将适用于任何数字系统。
Jeffrey L Whitledge,

5
错误报告:应该未知的时候,报告14.65为奇数。
TheSoftwareJedi

4
软件Jedi,这是一个“功能”。;)
Sklivvz

31
TheSoftwareJedi:14.65是我见过的最奇怪的整数之一。
布鲁斯·奥尔德曼

16

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

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

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

像这样检查:

isEven = (x & 1);

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

但是,我认为以下情况适用于所有情况:

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

感谢ffpf指出文本框在我少于字符之后就吃掉了所有东西!


我认为您的第二个代码示例缺少一些文本。
杰夫·耶茨

3
让我们补充一下这些数字吧!
thejh 2013年

14

一个不错的是:

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


1
这不能很好地处理isOdd(0)。
史蒂夫·麦克劳德

1
我认为对于具有任何偶数值的isOdd()或具有任何奇数值的isEven(),您都具有无限循环(具有尾递归)或堆栈溢出(无尾递归)。它仅以true结尾。这再次是停顿的问题。
Jeffrey L Whitledge,

7
哦,当然,不加评论地修正它,让我看起来像个白痴。没关系。
Jeffrey L Whitledge,

1
现在,您遇到了一个编译错误:在isEven中,并非所有代码路径都返回一个值。不,我实际上没有尝试过这段代码,是我脑子里的编译器在抱怨。
Jeffrey L Whitledge,

5
编译错误:不是所有的路径返回值与恨你的示例代码的bug评论轰炸你,但是当你打电话时会发生什么ISEVEN(5)
凯文-

11

如果将数字除以2,则余数为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为负奇数。
WMR

那就是为什么你对我不满意?
jjnguy,

3
我之所以投票,是因为您在C语言中输入的功能比输入的字符更多。IE num%I是7个字符,其中空格IsOdd(I)是8个字符。为什么要创建一个比仅执行操作还要长的功能?
凯文

13
在我看来,@ Kevin不是用字符来衡量的,而是用编写它所花费的时间(包括思考+调试时间)来衡量的。num%2比isOdd多花了毫秒的时间。现在将数字加到全球,您就失去了一个集体年份。还可以对isOdd进行测试,验证,并最终通过无错误认证(例如,处理负数),其中num%2-一些开发人员总是会产生疑问并开始尝试。好的代码就是您不用编写的代码,只需重复使用……仅是我的2美分。
伊兰·棉兰

2
@EranMedan,同样的逻辑适用于用IncrementByOne(i)替换i ++,这也是一个坏主意。如果开发人员对num%2的功能有疑问,我不希望他或她靠近我的代码。
凯文(Kevin)


7

我想说的是将其除以2,如果余数为0,则为偶数,否则为奇数。

使用模量(%)可以简化这一过程。

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


6

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

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

  }
  return half1 == half2;
}

不,您不是我指望的那种孩子:)
尤金斯克(Eugensk)

我本来打算对此表示赞成,但对于负数来说有点慢。:)
克里斯·杨

3
所有数字都是明亮积极的。还是对某些偏见?:))
eugensk

3
在计算机中,所有数字曾经为负,最终变为正。我们称其为幸福滚转(不适用于BIGNUMS,YMMY,并非在所有州都有效)。
Will Hartung

@WillHartung的“幸福滚滚”很棒!:D
thejh

6

我会建立一个整数的奇偶校验表(如果是奇数,则为1,如果是偶数,则为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];
}

因此,让我们改为使用偶数和奇数的数学定义。

即使存在整数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整数是整数的子集。)

现在,人们可能会担心,对于C整数中的给定n,C整数中可能不存在相应的整数k。但是只要有一点证明,就可以证明对于所有整数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为偶数,则ak确实存在,但我不会在这里证明。如果n不为偶数,则循环even无论如何都不会提前返回,因此没关系。)但是,这意味着k <n如果n (*)不为0,并且事实(在这里再次证明)对于整数m而言,z以整数2m = z表示z不等于m。在n为0的情况下,2 * 0 = 0所以0就算完成了(如果n = 0则0在C整数中,因为n在函数中的C整数中even,因此k = 0在C整数中)。因此,如果n是偶数,则C整数中的n存在于C整数中的ak。

类似的论点表明,如果n为奇数,则C整数中存在ak,因此n = 2k + 1。

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


1
我的意思不是冒犯,但是这个答案的意义是什么?i % 2更小,效率可能更高。
GManNickG

2
@GMan:但这更具确定性!这将正确检测所有边缘情况。
P Daddy

1
... AND(!!!)是正确的!
托马斯·爱丁

我不知道你是否在开玩笑。:X %2适用于所有整数。
GManNickG

1
+1:我想说“好答案”,但我认为“有趣的答案”更合适。
詹姆斯•韦伯斯特

5
// C#
bool isEven = ((i % 2) == 0);

2
什么?那不是C#!那是纯C!:-P
asterite,

8
我将使用WinForm使其成为纯C#...
Michael Petrotta

@mateusza:通常,当您在大写字母中看到“布尔”或在C中看到其他字母时,它是“ typedef或” #define或“某物”。
David Thornley,2010年

2
@mateusza @大卫索恩利在C99布尔是一个标准功能(en.wikipedia.org/wiki/Stdbool.h
FORTRAN

1
谈论多余的括号...
Thomas Eding

4

这是Java的答案:

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

4

试试这个: return (((a>>1)<<1) == a)

例:

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

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

你能解释一下吗?我不熟悉按位运算符
Abdul

向右然后向左移动将使您的最后一位(最右边的一位)清零。如果新数字与原始数字相同,则意味着原始数字的最后一位为0。因此为偶数。看看我最新的答案。
Kiril Aleksandrov 2015年

谢谢,我现在知道了
Abdul

我不确定哪种方法更快。我没有尝试对它们进行基准测试。
Kiril Aleksandrov'8

难道这也不会使您最重要的部分归零吗?某些语言中的无符号整数和大多数语言中的负整数的问题……
Troyseph 2015年

4

在阅读了这个有趣的讨论之后,我记得我有一个真实的,对时间敏感的函数,该函数在主循环中测试了奇数和偶数。它是一个整数幂函数,发布在StackOverflow的其他位置,如下所示。基准相当令人惊讶。至少在此实际功能中,模数较慢,并且明显如此。获胜者大都需要模数时间的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%方法

对于认为理论或汇编语言清单解决了此类争论的人们,这应该是一个警告性的故事。Horatio在天地上的事物比您的哲学梦想中的要多。


1
最好使用unsigned xx = x >> 1;实现定义的行为时x < 0。不清楚原因xOrMask类型。足够简单,可以使用while(x)测试进行重写。
chux-恢复莫妮卡

2
我想知道您使用哪个编译器作为基准,因为大多数编译器应该足够聪明,可以% 2使用按位编译情况&。我刚刚进行了测试,结果是完全相同的(VS2015,带有所有优化功能的Release版本,包括x86和x64)。公认的答案也针对GCC(写于2008年)说明了这一点。

2
这篇文章的问题是,在任何平台/编译器上,按位运算的or速度都快于一个前提的前提and是不可能的。即使平台/编译器组合如此怪异(并且您既没有发布该组合,也没有发布用于执行基准测试的代码),但依靠其他编译器执行相同的操作将是一个糟糕的优化选择。因此,正如我所写的,我想知道在哪个平台/编译器上进行了测试,因为我几乎可以肯定它没有正确地测量。
Lou

2
不称您为说谎者,只是断言您没有正确衡量自己。无需称呼我为卡车司机,请阅读我的原始评论:我确实做了一个基准测试,并且在所有三种情况下,结果都完全一样(确定性为〜3 sigma,在每次测试10次并运行了500.000之后, .000次迭代)。如果您确实有一个杰出的长期职业,请退后一步,考虑您的主张是否合理,然后发布用于进行基准测试的实际代码。否则,我认为是该职位,只是衡量上的一个错误。

1
完成

4

这是@RocketRoy讨论的后续内容 他的答案,但对于想要比较这些结果的任何人来说可能很有用。

tl; dr从我所见,Roy的方法((0xFFFFFFFF == (x | 0xFFFFFFFE))并未完全优化x & 1mod方法,但是实际上在所有情况下运行时间都应该相等。

所以,首先我比较了使用 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,发布版本,未连接调试器)。

发布程序集使用test针对and和的指令mod,而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定义,并在需要时实施此定义,摘自此答案)。

#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:由于三种情况下的所有输出都完全相同(嗯,在一种情况下,对于您的程序来说,情况稍差一些),所以我真的不在乎使用了多少个寄存器。但是,再次重申一下,可以随意创建和发布这样的示例程序/环境,在所有其他情况相同的情况下,在一种情况下,这会使编译器创建更优化的程序集。

我总是喜欢自大的程序员。对于程序员而言,这是一个很好的特征,但是在更复杂的真实程序中,我的方法的性能会比您的方法好,因为编译器拥有更多解决问题的方法,因此指令重叠(在Intel架构上)产生了更好的结果。 。很少有具有良好基准测试经验的资深程序员会喜欢您的基准测试,但是会继续努力,并记得在新芯片发布时重新运行基准测试。事情确实会随着时间而改变。

3

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

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

现在您可以执行以下操作

int i = 5;
if (i.IsOdd())
{
    // Do something...
}

1
好的代码。可惜它声称2是奇数,而3不是。
安东尼

糟糕,抱歉...我的逻辑是错误的...
rudigrobler

3

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

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

2

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


2

IsOdd(int x){返回true; }

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


2

便携式:

i % 2 ? odd : even;

不可携带:

i & 1 ? odd : even;

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

2

正如某些人所张贴的,有很多方法可以做到这一点。根据该网站,最快的方法是模运算符:

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

但是,这是作者标记其他一些代码,运行速度比上面的普通模运算慢:

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方法,或者为什么要使用它?



1

为了让我们中那些在研究过程中没有做布尔布尔代数的人更多地了解按位算子方法,这里有一个解释。可能对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
}

抱歉,这是多余的。


1

数字零校验| 零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这篇Wikipedia文章零奇偶校验是错误的。这篇文章欺骗了很多人。在眨眨眼之前要三思。

1
你是对的。现在,我已经阅读了其他答案,我发现您的答案最全面:)
el.pescado15年

@ el.pescado。谢谢。:)现在,您是Zero的最好朋友。(拥抱)

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

0

为了讨论...

您只需要查看任何给定数字中的最后一位数字,看看它是偶数还是奇数。有符号,无符号,肯定,否定-就此而言,它们都是相同的。因此,这应该全面工作:-

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:我浪费的更多,不是吗?:-)也可以相乘和相减。但是,我不敢说这两种解决方案之间最有效的方法。从来没有声称这是最快的解决方案,如果您再次阅读我的文章的第一行,则相反。
2008年

@Tooony,啊,我的幽默帽掉下来了。现在正式恢复了:D对不起:)
自由空间

0

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


-1:如果要提高效率,请使用其中任一个。如果您希望它具有便携性,请使用%。如果您希望它可读,请使用%。嗯,我在这里看到一个图案。
Thomas Eding

@trinithis,没有模式,此解决方案比您的解决方案好得多。
Subs 2012年

0

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

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

我们只需要检查任何数字的可除性,并使用%运算符检查可除性

如果使用其他则检查偶数

if(num%2 ==0)  
{
    printf("Even");
}
else
{
    printf("Odd");
}

C程序检查是否使用偶数或奇数

使用条件/三元运算符

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

使用条件运算符检查偶数或奇数的C程序

使用按位运算符

if(num & 1)  
{
    printf("Odd");
}
else 
{
    printf("Even");
}

三元运算符到底在哪里?
Beyondo

0

+ 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运算符检查在我们最右边的位行如果是1

认为它是对与错

当我们将n1进行比较时,表示0001二进制(零的数量无关紧要)。
然后让我们想象一下,我们有一个整数n,其大小为1个字节。

用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 & 1T rue。

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

只需更改n & 1为二进制n & 2表示2 0010

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.